How does one protect against XSRF attacks in Grails. I see that forms support the notion of useToken which (I think should suffice). However, remoteForm or other AJAX related request don't support this feature.
Also, is there a way to invert the functionality of useToken so that it is always used rather than enabled on a case by case basis?
You could try looking at the source code of the <g:form> tag. It uses a SynchronizerToken to create a token and store it in the session. Based on the resolution of this issue it should be possible to use the same token for all forms on the same page. I did not try this, but theoretically you would just need to manually create a hidden field on the form and generate the token in that field.
We have inject a hidden value to the request object in a before filter and encrypt the value with a specific key. We then inject that request.token value to every form on the site and when we receive a POST we have a before filter to verify that that hidden field is present and its value can be decoded by that same secret key.
If that hidden value is not present or if it is stale -- we use a timestamp as payload -- we give the client an error status.
This is an alternative way to what was described above and we use this, because we do not use sessions on our sites to make it easier to load balance.
Related
I am working with the eBay API using OAuth on my current Meteor project app.
There is a section of the app where I can create an eBay account profile, and assign custom values to the account (such as nick-naming it, etc.). This is where I initiate the OAuth sign-in redirect process.
My question is about the 'state' parameter in the token requests. I understand that it is for helping prevent CSRF, but do I HAVE to use it that way? 'state' does seem to be optional after all.
Let's say I wanted to pass another value into the request call such as the string 'eBay Seller', and expect that the same exact string be returned in the response. I want to use that value to help my app determine which account to assign the returned tokens to (based on which account profile initiated the redirect link).
Is 'state' a valid place to pass in a variable that I expect to be returned exactly as sent? I considered using Session variables to handle this scenario, but quickly realized that this would not work, since the OAuth process takes me outside of my project's domain.
Does OAuth support passing variables that are expected to be returned as sent? Is sending my variable as 'state' allowed or even recommended (or absolutely not recommended?) Is there a better way to achieve what I want to do that does not involve updating database values?
Thank you!
You can send what you want as state. You should try to make sure it's not guessable though, to mitigate against CSRF attacks.
If you want to return useful information like 'ebay seller' then include something for CSRF (e.g. hash of the session key id) and the text 'ebay seller' and delimit them e.g.
2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824|ebay seller
Now you have the best of both worlds: useful state info + CSRF protection.
Your redirect endpoint logic can check the hash of the session id matches and also confirm the account type from the initial request.
I want to encrypt Yii2 URL parameters
Example: http://localhost/school/backend/web/index.php?r=user%2Fview&id=20
20 must be encrypt.
Whats the simplest way in Yii2 to achieve this.
The problem with trying to encrypt part of the URL like that is that the client browser must have the key to use for the encryption. You can supply that over HTTPS but it would mean that anyone could also obtain the key. Alternatively you could have one key per browsing session, but that will impact performance and may be overkill.
What's the reason for encrypting the id parameter? If it's just to avoid an insecure direct object reference then you could create a hash for the user based on random data (you'd need a unique hash for each user object). The hash would make it difficult, but not impossible, to correctly guess another object's hash. Essentially this is security by obscurity.
A better approach is to securely handle viewing other IDs. For example, it may be that I'm allowed to view my own objects / users but not yours. To achieve this you should programmatically check the user is authorised to view the object in question. This does mean writing more code but is a significantly better way of doing things.
Submitting the request by HTTP POST would only protect you from a casual user. A more skilled user (or attacker) would just intercept the POST request, modify the value and send it on.
A common use case for WebAPI would be to have shell views rendered by MVC controllers, which contain javascript that then hit your API to access data.
But let's say you have some expensive API operations and you don't want people remotely accessing those endpoints -- you only want your MVC views, delivered by your application, to access them. How could you go about protecting them?
In this case Request.IsLocal doesn't work, because javascript is invoking it from the client's browser on their machine. Even if it did work, you need to dig to get the real HttpContext in order to find this property -- and that solution wouldn't work in self-hosted WebAPI.
For API endpoints that require a valid IPrincipal, you could protect them with the [Authorize] attribute. But what about API endpoints that you want your app to be able to access for anonymous users?
I have tried a solution and will post it separately as an answer, because I'm not sure if it's the best (or even a good) approach.
If your MVC site uses authentication, you could enable forms authentication for your Web API methods. You could write a custom [Authorize] attribute that will check for the presence of a forms authentication cookie which will be sent from the AJAX call and if present construct the principal.
Another possible solution is to protect your API with tokens which is a more RESTful style. The idea here is that when a user authenticates on your MVC website you could generate and pass a token to the view which will be used when sending the AJAX request to the Web API which in turn will verify the validity of the token and its signature.
If on the other hand your site doesn't use authentication, then things will get very complicated because you have no way of knowing whether the request comes from a trusted client since you are using javascript to call your API methods.
Before you go harping about "what have you tried", here is what I have tried. It works. Just not sure if there is a better way.
Create an MVC action filter and add it as a global filter during Application_Start.
Create an Http (WebAPI) action filter and use it on actions that should reject remote requests.
The global MVC filter does this:
Looks for a specific cookie in the request. If the cookie is there, its value is decrypted. The decrypted value should be a string representation of a DateTime, so use DateTime.TryParse to get it out. If the value is correctly parsed to a DateTime, and that DateTime is less than a day old, STOP HERE and do nothing else.
If the cookie is not there, or cannot be decrypted / parsed, or is older than a day, write a new cookie to the browser. Use the current DateTime.UtcNow.ToString() as the value, encrypt it, and write it with HttpOnly = false.
The WebAPI filter does this:
Looks for a specific cookie in the request. If the cookie is there, decrypt its value and try to parse it out as a DateTime.
If the value is a valid DateTime and is less than 2 days old, STOP HERE and do nothing else.
Otherwise, throw a 403 Forbidden exception.
A couple of notes about my current implementation of this. First of all, I use AES encryption with a shared secret and a salt. The shared secret is stored as an appSetting in web.config. For the salt, I enabled anonymous identification and used Request.AnonymousID as the salt. I'm not entirely fond of the salt because it's tricker to get at in a WebAPI controller, but not impossible as long as it is not self-hosted.
Is it possible to pass a session via a hidden form field? (ie POST)
if so if it possible to between the standard method and field sessions on a per controller bases without losing information?
If cookies are disabled, CGI:Sessions will automatically switch to using hidden fields, however, I'm not certain exactly how this behavior is supported in Rails. Moreover, changing this behavior to require the use of hidden fields may require modifying CGI:Session.
If the client has cookies disabled, the session id must be included as a parameter of all requests sent by the client to the server. The CGI::Session class in conjunction with the CGI class will transparently add the session id as a hidden input field to all forms generated using the CGI#form() HTML generation method. No built-in support is provided for other mechanisms, such as URL re-writing. The caller is responsible for extracting the session id from the session_id attribute and manually encoding it in URLs and adding it as a hidden input to HTML forms created by other mechanisms. Also, session expiry is not automatically handled.
Therefore, it should be possible to use this method, but as far as I know, it's not supported as a simple option in Rails.
To be clear, even ActiveRecord Session Store uses cookies, so don't equate session stores with how session data is handled by the client.
Finally, at one time there were plugins to support this behavior, but these plugins are old, don't appear to support Rails 3. See the "Non-cookie session" section of Sessions & Cookies in Ruby on Rails
I have read the section on header injections as described here: http://guides.rubyonrails.org/security.html. But I can't seem to walk through a step by step example of this in my head. Could someone walk me through an example of how exploiting the referer header could cause issues in an application?
It is very simple:
A malicious user can insert due to a vulnerability in earlier versions of Ruby and RoR a secuence of URL encoded characters ā%0d%0aā that are the equivalent for ā\r\nā which is a carriage-return and line-feed.
In this way a new lines in the header can be injected with new information as cookies, redirections, referers and any other information that can be used to help the attacker to commit his purpose.
As example maybe the one in the link you sent is not exactly the best, but think about a cookie validation to access a private site. Some sites use to locate a cookie to a value like "true" or "1" once the user pass trough the validation process. If you insert into the header the cookie value without passing the validation process you should access the private pages without the need of login into the application.