An extremely common and dangerous flaw in web apps security is relying solely
in client side security as we already discussed on this blog
here
and
here.
On this post we’ll examine the most frequent mistakes developers make and how
to protect from them. But before we proceed, check our previous discussions on
web application security. For all the topics on security, please
click here.
Law of Security #4
We already reviewed the
10 laws of security on this blog. So, you may recall our
Law #4:
If you allow a bad guy to upload programs to your Web site, it’s not your
website any more.
That's probably, the main (but not the only) reason why web applications are so
insecure: users are constantly submitting data to your application and changing
data state. So what should we do?
Should you trust all data being submitted to you?
No.
Can you trust data from cookies sent to you?
No.
Can you trust everything that you are getting in your web application layer?
Of course not.
You cannot trust client side security
Because you don’t have control of what runs on your client or how that
information is being submitted - if it was manipulated or came from a different
source than you expect - you should
never trust the data you are getting in a request. That's why you should
always re-validate in your server data sent to you. The only actual info you
should trust is the session, stored on the server.
So what are the most common mistakes?
In the context of web applications, the most common mistakes web developers make
are:
- Hiding info in hidden fields
- Relying on Http cookies
- Relying on Url parameters
- Using Form action urls for backend logic
- Using the Referer header for backend logic
- Trying to be cryptic or to obfuscate info
- Rely purely on the ASP.Net Viewstate
- Rely only on html form attributes
- Only run Javascript validation
Mistake #1 - Hiding info in hidden fields
In the past, developers used to hide essential information in hidden form fields
as:
<input type=”hidden” name=”price” value=”45”>
So when a post was submitted to the server, something like the below would be
sent:
POST /page.aspx HTTP/1.1
Host: mysite.net
Content-Type:
application/x-www-form-urlencoded
Content-Length: 20
quantity=1&price=449
Hacking this application is as simple as:
- changing the price value using devtools and resubmitting the form;
- issuing a post from a different tool to the server.
Luckily, this anti-pattern is no longer common anymore.
Solution
The solution here is simlpy not use hidden fields to pass sensitive information
to the client. Use the Id of the product or some other type of identifier
instead.
Mistake #2 - Relying on HTTP cookies
This one is less common but is still being used. Developers are still saving
sensitive information in cookies, which are stored in the client side and can be
easily manipulated. Consider this response from the server:
HTTP/1.1 200 OK
Set-Cookie: Discount=20
Content-Length: 100
Assuming that the Discount value set in the cookie was used to perform some
calculation in the server, a malicious user could easily change that information
to 100 for example, and get the product for free. Not what we want.
POST /store.aspx HTTP/1.1
Cookie: Discount=100
Content-Length: 10
Solution
The solution here is simlpy not use cookies fields to exchange/store sensitive
information to the client. If you need to save, save it on the session, on the
server. Upon each request, get the session value and process it from there.
Mistake #3 - Relying on Url parameters
Often, urls are very easily hackeable:
somesite.com/store/view?prod=3&price=100
Anyone using a web browser or
curl for
example could alter that url and, if that property was used to provide the price
to the server, alter it and benefit from your security issue. Others can be more obscure but also open to attacks:
somesite.com/store/view?prod=3&price=100&price_tkn=VJ58k6UxCFdUHiVj
Remember that
security trough obscurity
does not work flawlessly.
Solution
Avoid using the query string to pass sensitive information. Even if some urls
are meant to be hackeable, that's not the objective here.
Mistake #4 - Using Form action urls for backend logic
Similar to mistake #3, hidden but still modifiable, form actions can also be
used to pass information :
<form action="/store/submit?discount=10">
...
</form>
Remember, this approach could be easily manipulated.
Solution
Avoid using the query string to pass sensitive information. Even if some urls
are meant to be hackeable, that's not the objective here.
Mistake #5 - Using the Referer header for backend logic
Less common, the Http Referer header can be used to simulated authentication
logic in the server. For example, a request like:
GET /auth/CreateUser.aspx HTTP/1.1
Host: mdsec.net
Referer:
https://mysite.com/auth/admin.aspx
Could be interpreted in the server that the user indeed came from the admin
page. While this could be true for non-malicious requests, it could also be
manipulated.
Solution
Avoid using the Referer for authentication as can be easily manipulated in the
client side.
Mistake #6 - Trying to be cryptic or to obfuscate info
We already provided an example in mistake #3. Trying to be cryptic or
obfuscating information is not a 100% reliable solution. Yes, it could be used
as part of a solution but should not be the sole solution.
Solution
Be creative securing your services and avoid
security trough obscurity.
Mistake #7 - Rely only on html form attributes
Html form attributes like maxlength and disabled are nice but can be easily
circumvented by simply removing them in developer tools or by submitting.
Example:
Solution
Keep using those components to provide more friendlier applications but never
rely only on them to validate your data. Always have similar validation in the
server and in the backend if necessary.
Mistake #8 - Only run Javascript validation
As in mistake #8, relying solely on javascript is highly insecure as javascript
can be disable or be easily removed, altered or manipulated in the client
machine.
Solution
Make use of javascript to serve more friendlier applications but never rely only
on it to validate your data. Always have similar validation in the server and in
the backend if necessary.
Conclusion
So there you are, hope this post has helped you identifying the threats your app
may be facing and how you could protect against them.
But only for your front end. Remember, security is complicated. Securing
your frontend is just another piece in the complex effort towards a good
security framework.
See Also
For more posts about
ASP.NET on this blog, please
click here.