Asp.mvc request validation - asp.net-mvc

I have an ASP.NET MVC 3 application in which I want to set
requestValidationMode="4.0"
and all areas of the website were a normal user has access have
ValidateInput(true)
SoI basically html encode all user input and save it encoded in the database. (The site is not meant to work without javascript)
My question is
How should I treat the signup, log in and change password functionality ?
Obviously I want to allow the user to insert whichever password he/she wants so,
Is it ok if for the password field I do html encode on the client and then html decode on the server, before saving the password in the database ?
Thank you

Given that passwords aren't ever likely to be displayed in cleartext (or even stored), XSS shouldn't be a concern for passwords.
You can decorate the password property(ies) of your (view) model with [AllowHtml]
I can't think of a reason why the password would need to be echoed back to the client from the server, so the Html sanitization step shouldn't be necessary? (Do password rules validation on the client)
Troy Hunt discusses this here.

Related

MVC: Password value is seen from page source

I have a very simple password box bind to a property. When user edit existing password, it displays as "......." we all know. The code is:
#Html.PasswordFor(m => m.Password, new { value = Model.Password })
However if you righ click and 'view page source', you will see the password in plain text, which seems cause security concern. Is there anyway to hide that? Thanks a lot!
There is pretty mush anything that you can do about it. Since it is a user input it's value has to be specified in some way before the form submit. Client side encryption/ decryption most probably won't work since client side code can not actually be secured. So if you use client side encryption (either symmetric or asymmetric) the hacker that has an access to the page source will be either able to see the encryption/decryption algorithm or to replace the password value to something he knows. So as I said if the hacker has an access to the view source of the page while user types a password there is nothing you can do. Even PCI compliant applications that send sensitive data over the web (for example credit card numbers) send the raw user input to some remote secure tokenization server that generates a token that will be used in subsequent requests.The major thing that Html.PasswordFor does it that is instead of displaying the password as flat string it masks if so if somebody behind your back looks on the display while you are typing the password he won't be able to see it. What you must do when submitting a password is to use https in order to prevent a man in the middle attack. And of course you should not store plain user passwords on the server (only their hash values) so they could not be leaked.
Well when you are binding the view with your model and setting the value from controller.
and it simply renders the html with all its values. That's the value of password is visible. #HTML.PasswordFor simply renders the password to the browser. You need to use encryption/decryption to save and retrieve the password to make sure it will be safe.

Getting past anti-CSRF to log a user into a site when you know their username and password

This sounds a bit evil, bear with me though. It's also not specifically a Rails question even though the two sites in question use Rails. (Apologies in advance for both these things)
Imagine two websites which both use Ruby on Rails:
mysite.com, on which i'm a developer and have full access in terms of changing code etc, and also have an admin login, so I can manage user accounts.
theirsite.com, on which i have an admin login but no dev access. I know the people who run it but i'd rather not ask them any favours for political reasons. That is an option however.
Using my admin login on each site i've made a user account for the same person. When they're logged into mysite.com, i'd like to be able to provide a button which logs them straight into theirsite.com. I have their username and password for theirsite.com stored in their user record in the mysite.com database, to facilitate this. The button is the submit button for a form which duplicates the form on the theirsite.com login page, with hidden fields for their username and password.
The stumbling block is that theirsite.com handles CSRF with an authenticity_token variable, which is failing validation when the login submits from mysite.com.
My first attempt to get past this was, in the mysite.com controller which loads the page with the form, to scrape the theirsite.com login page to get an authenticity token, and then plug that into my form. But this isn't working.
If i load the theirsite.com login page, and the mysite.com page with the remote login button in two browser tabs, and manually copy the authenticity_token from the theirsite.com form to the mysite.com form, then it works. This is because (i think) the authenticity_token is linked to my session via a cookie, and when i do it all in the same browser the session matches up, but when i get the authenticity token from theirsite.com via scraping (using Nokogiri but i could use curl instead) it's not the same session.
Question A) So, i think that i also need to set a cookie so that the session matches up between the browser and the Nokogiri request that i make. But, this might be impossible, and exactly the sort of thing that the anti-CSRF system was designed to defeat. Is that the case?
Question B) Let's say that i decide that, despite the politics, i need to ask the owner of theirsite.com to make a small change to allow me to log our users into theirsite.com when we know their theirsite.com username and password. What would be the smallest, safest change that i could ask them to make to allow this?
Please feel free to say "Get off SO you evil blackhat", i think that's a valid response. The question is a bit dodgy.
A) No, this is not possible as CSRF Protection is made to protect from actions like these only. So "Get off SO you evil blackhat"
As per the question I'm assuming that theirsite.com is using Rails(v3 or v4)
B) The smallest change that you could ask them to do is to make a special action for you, so that you could pass user credentials from your back-end and the user will be logged in from their on.
That action will work something like this :
You'll have a special code which will be passed along the credentials so that the request is verified on their servers. That code can either be a static predefined code or it can be generated on minute/hour/day basis with the same algorithm on both sites.
The function that you'd be asking to make for you will be like this:
Rails v3 and v4:
This action will be POST only.
#I'm supposing 'protect_from_forgery' is already done in theirsite.com
class ApplicationController < ActionController::Base
protect_from_forgery
end
#changes to be made are here as follows
class SomeController < ApplicationController
skip_before_filter :verify_authenticity_token, only: [:login_outside] #this turns off CSRF protection on specific actions
def login_outside
if(#check special code here)
#Their login logic here
end
end
end
Check this link for further information on skipping CSRF protection in Rails
Rails 4 RequestForgeryProtection
This shouldn't be too hard to do.
You need to send an ajax GET request to their signup page, copy the authenticity_token with javascript, and then send an ajax POST to the actual log in route that creates a session with the right credentials and authenticity_token.
One tricky part is finding out their log in route. Try /sessions/new or perhaps they have the url in the form, so look at the html there. Good luck!
The other tricky part is knowing how the parameters are usually sent. Check out the form's html. If all the input tags have user_ before their name's then you'll need to structure your parameters similarly; i.e. user_email, user_password.
It's entirely possible to fetch the crsf token and submit your own form (because a log-in page is accessible to anyone!). However, it'll be difficult to know the details of their arrangement. The guessing and checking isn't too bad of an options (again, /sessions/new is how I route my log in; you should also try your route to see if they have a similar one.)
If that doesn't work, try taking a look at their github account! It's very possible they haven't paid $7 a month and it's open to the public. You will easily be able to view their routes and parameter parsings that way.
Good luck!
This is impossible. The anti-csrf works like you send cookie to an user, and inject token in form of hidden field into a form; if the token matches with cookie form post is accepted. Now if you run form on your side, you can't set the cookie (as the cookie can be only set in domain of its origin).
If there is just some particular action you want to perform on their site, you can get away with browser automation. (i.e. your run browser on your server-side, script the action and execute it).
As for B) safest and smallest change is contradiction :) Smallest change would be to create handler for POST request on their side where you'll send username and password (this handler HAS TO run over https) and it will create auth cookie on their side.
As for safest - the whole concept of storing encrypted (not hashed) passwords is questionable at best (would you like your site to be listed here http://plaintextoffenders.com/ ?). Also if user changes his password on their side you're screwed. Secure solution would be that you'll store just 3pty UserID on your side, and you'll send asymmetrically encrypted UserID with Timestamp to their side (you'll encrypt it with your private key). They'll decrypt it (they'll have to have public key), validate if timestamp is not to old and if not they'll create auth cookie for given user id. There are also protocols for that (like SAML).
A)
What you are trying to do is really a form of a CSRF attack.
The idea behind a cross-site request forgery attack is that an attacker tricks a browser into performing an action as a user on some site, as the user who is using the site. The user is usually identified by a session identifier stored in a cookie, and cookies are sent along automatically. This means that without protection, an attacker would be able to perform actions on the target site.
To prevent CSRF, a site typically includes an anti-CSRF token in pages, which is tied to the session and is sent along in requests made from the legitimate site.
This works because the token is unpredictable, and the attacker cannot read the token value from the legitimate site's pages.
I could list various ways in which CSRF protection may be bypassed, but these all depend on on an incorrect implementation of the anti-CSRF mechanism. If you manage to do so, you have found a security vulnerability in theirsite.com.
For more background information about CSRF, see https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF).
B)
The smallest change which theirsite.com could do is to disable the CSRF protection check for the login page.
CSRF protection depends on the unpredictability of requests, and for login pages, the secret password itself protects against CSRF. An extra check through an anti-CSRF token is unnecessary.

AntiForgeryToken in MVC - why there's need in both cookie and form field

I can't get why during validation MVC takes into account not only form field but also a cookie with the same information. Looked through different SO answers and blogs but couldn't find the answer.
For instance, victim can transfer money on a http://bank.com using his authentication cookie.
Then an attacker send an email to a victim with such an image <img src="http://bank.example.com/withdraw?account=Alice&amount=1000000&for=Mallory">. Why just not to prevent the malicious request by comparing only the form field "__RequestVerificationToken" with some hash? Using the cookie seems to me a bit extra-stuff. Could you provide some scenario which "break" my hunch?

What is the appropriate way to post/submit login information from razor view to controller action?

In my view, I have #html.passwordfor, it in contained within a #html.beginform. When the user clicks submit and the form is posted back to the controller, the password is available in plain text in the http request body.
What is the correct way to convert that user entered password to a securestring type prior to it being sent to the controller checklogin action?
I assume it is something to do with the securestring type because I am passing the password (and username) to the constructor of NetworkCredential which has an overload allowing a securestring password rather than a plain text password.
The way html forms are designed; the credentials are sent in the clear between you and the server. There is no default way of encrypting data that will ensure security. You can try to use some JavaScript libraries to encrypt the password prior to sending it; but if you are worried about someone intercepting the password; they would be able to intercept your encryption algorithms as well.
The common method of ensuring that the passwords and other sensitive information (Credit cards etc) are secure is to use SSL. This encrypts the entire connection between the client and the server; and it much more secure.

How to manually validate user in ASP.NET MVC Internet Application template

I'm new to web security so I don't want to implement my own. I plan to use SimpleMembership via the VS2012 template for an ASP.NET MVC Internet Application. The problem is that I need to pass the data via a Web API.
I plan to use basic authentication for my Web API, so I just need to pass username/pass in the http headers. I can intercept the message using Thinktecure.IdentityModel. Here's an example that uses ASP.NET Membership:
authConfig.AddBasicAuthentication((userName, password) =>
Membership.ValidateUser(userName, password));
I can replace Membership.ValidateUser with my own bool function. I've successfully queried my custom database with username/password and everything worked fine. However, I'm using the template's user database because I DON'T want to store string (or even encoded) passwords.
I am unclear on how to manually validate the credentials using the SimpleMembership's database. I can grab a UserProfile, but can't figure out how to check the profile's password.
UserProfile user = context.UserProfiles.Find(1);
==OUTPUT==
user
UserId: 1
UserName: "bob"
Do you know how I can check if an inputted password matches that of an existing user?
Thanks for your help!
Why you are not using Membership.ValidateUser? This is not restricted to just ASP.NET Membership assuming you have your [InitializeSimpleMembership] (here) attribute in the correct places or have executed the logic inside it yourself elsewhere, and you have the correct references to WebMatrix etc you can still just call Membership.ValidateUser and it will use SimpleMemberships Validate user.
If you wanted to go to the database yourself, and assuming you are using hashed password etc then this article is probably going to help as you are going to need to hash your inputed password before selecting it out, the rest of which is just writing some EF or (any other db access method) to select from the User table where the username and hashed passwords match. But I can think of no obvious reason to do this as Membership.ValidateUser will do all this for you.

Resources