Bookmarklet security considerations, CSRF, hashed key - security

My bookmarklet can be called from any website and basically allows the user to insert a row into his collection from afar - if he is logged in.
Now I want to enable CSRF protection for my site and since a bookmarklet is basically non-forged cross site request, I thought about how I could tell it apart from forged ones.
It's not a high-security environment, but I'm also interested in principle.
I thought I had a way to do it figured out, but then realised that it had problems galore.
Original idea
generate a random key that is included in the bookmarklet-link. The key's hash is saved in the database. The random key allows access ONLY to the privilege of insertion into this collection and can't be used anywhere else.
the bookmarklet loads a longer script from my server, so I could supply a CSRF prevention token this way
require the user to be logged in
Problems
If I have the bookmarklet key, do I need counter-CSRF tokens?
Is there any way that I could protect the bookmarklet key if the user clicks his bookmarklet on a malicious website?
I don't want username and password to be stored in the bookmarklet link, because anybody who has access to the computer would get the password as well then, so I decided on the random key.
but if I store only the hash, I cannot generate the same bookmarklet link twice, so when the user wants a bookmarklet in another browser/computer he tediously has to import the link from the old one or break support for the old one.
but I shouldn't store the cleartext key, because someone who gains access to the database could use this key to insert rows into accounts that don't belong to him.
Possible solution I could ask the user to provide his password anytime he creates the bookmarklet and hash the password many times and put that hash in the URL and put the hash of that hash my database. But of course this opens much worse security holes.
I could do this with something like "Mother's maiden name" instead
I cannot use bcrypt for hashing because of the random salt, right? What hash function would be right? Or would you dismiss the whole idea?
If I leave the bookmarklet key out, a malicious website could simply embed the bookmarklet and extract a valid CSRF token from it, right?
Better ideas? Or can't you have CSR without the F?
Edit, specified use case
One thing I simply didn't think about, is the usage of an iframe as suggested by Sripathi Krishnan.
I had not specified my use case, so yes, an iframe is a valid solution to the aforementioned
problem.
However, actually my bookmarklet at the moment does do some basic interaction with the website at runtime (meaning the form is there already and the user can change his selection in the website DOM which should change the form). I'm ready to dismiss this functionality for my use case, if it turns out, there's no reasonably-secure way to tell apart forged from non-forged cross-site requests - but I'm still interested on a theoretical level.

You can't make cross-site requests without eliminating the forgery part. But for your use case, I don't think you need cross-site requests.
Lets assume your service allows users to bookmark any pages he wishes. The job of the bookmarklet would be to save {url, title} into the database. At the same time, you want to prevent a malicious website automatically saving urls for a user who is logged in.
Here's what I would do to solve this -
Create a page on your domain that has a standard html form with regular CSRF protection. This page takes in the parameters {url, pagetitle}, but will only save this tuple when the user explicitly clicks the "save" button.
The bookmarklet's job is to load the iframe
Once the iframe loads, its a normal same-origin request
This is more or less what Google reader does as part of its bookmarklet. Here is the code for its bookmarklet - notice it doesn't have any tokens
javascript:
var b=document.body;
var GR________bookmarklet_domain='http://www.google.com';
if(b&&!document.xmlVersion) {
void(z=document.createElement('script'));
void(z.src='http://www.google.com/reader/ui/link-bookmarklet.js');
void(b.appendChild(z));
}
else{}
EDIT :
You can still support interactions with the iframe approach. The bookmarklet executes in context of the website, so it has access to the DOM. You can interact however you want with the website. When you are ready to save, open up the Iframe. The iframe will be a sort-of confirmation screen with just one save button.
The trick is to delay creation of the iframe. You only create the iframe when the user is ready to save.

If the bookmarklet is being stored in a web browser then the idea of including a secret key which hashed in the database is a good idea. This will prevent CSRF, although it is not ideal because in a sense this is a session id that doesn't time out. It should be clear that this token is only being used for this bookmarklet action. Despite this limitation it is unlikely that you will experience an attack. Adding HTTPS will make this stronger because it will be harder to spill this token.
If the bookmarklet is originating from a 3rd party site, then there is nothing you can do. This is the definition of CSRF.

Related

When to use random tokens to prevent XSS?

This isn't a language specific question, but I am using PHP5.
I am working on a project that has some amount of PII. Legally we are required to secure this data from hacking attempts, and because of that I have been researching best practices for defending common attack types. Obviously all database calls are using parameterized queries, and all data provided by the user is sanitized to prevent injection. I have also implemented sessions and methods to prevent session hijacking.
When it comes to defending against XSS attacks on forms, best practice seems to be to include a hidden input with a form token, then after the post to check the tokens match. There are further ways to make this more secure.
I have imagined one type of attack and haven't found a solution for it. What if a malicious site loads a hidden iframe pointed at my site (eg, view-member.php?id=1234) and because the victim user is logged into my site, their session continues in that iframe. What is stopping this malicious site from iterating through the IDs and ripping the data to get ahold of PII? Should I be creating a unique token for each page view, and checking that token when the page loads?
I am not 100% sure, but assuming my site is using HTTPS, the browser should warn the user and/or prevent the connection. Is that correct? Is that enough security?
In fact, everytime you present a form or any kind of interaction, you should include a randomized, verifiable piece of information that changes every time. This is not for preventing XSS but CSRF: https://en.wikipedia.org/wiki/Cross-site_request_forgery
The main problem is: An attacker can just send automated requests to your input-handling script without going through the "pain" of filling in your form manually (or even visit your page).
However, you won't prevent XSS attacks with this technique, as XSS attacks are mainly user input containing executable code (javascript) that is not filtered by the input validation. So to prevent XSS as well, you should always make sure not to deliver unfiltered user-generated content anywhere.
HTTPS won't help you in either case unless you use client-side certificates that allow access to your website only from trusted clients. HTTPS mainly acts as a transmission scrambler and identity verifier but does not prevent a bot from sending valid (but malicious) data to your form.
Hosting a website in an iFrame does not grant the attacker the permission to read cookies or information from the target page (that would be awful) as long as you follow the same-origin policy: https://en.wikipedia.org/wiki/Same-origin_policy
With this, only domains you whitelist will get access to information hosted on your page.

GET vs. POST in Session Validation

So I just read this article by Jeff Atwood and I wanted to make sure I understand it correctly as to how it applies to my use case. I am trying to validate a session for silent login. For security purposes this should be done with a POST right? Does it matter? I am just passing the sessionID and username from the cookie.
When it comes to CSRF (Cross-site request forgery), you can cause a user to take any action on any site which they are logged in to provided that the action requires only a GET. Forcing this to be done over a POST request defeats the approach of embedding an image, script tag, whatever in another page.
Even POST isn't completely secure in this scenario. There are other ways to mount a CSRF attack on a site using POST. Clickjacking/UI-Redressing enables another site to trick a user into submitting a form to a different website.
Basically the best way to validate is to add an automatically generated, hidden form element. You can store this inside your session data (Example: $_SESSION for PHP) so that you only need to generate a token at the start of a session. Of course, an attack could try do something like clickjacking (mentioned above) in combination with a iframe pointing directly to your site and possibly some JS to hide things a little.
For anything important you should re-prompt the user for their password, thereby greatly diminishing the value of any successful CSRF attacks.

How do I protect sensitive information from cross site access?

My web application displays some sensitive information to a logged in user. The user visits another site without explicitly logging out of my site first. How do I ensure that the other site can not access the sensitive information without accept from me or the user?
If for example my sensitive data is in JavaScript format, the other site can include it in a script tag and read the side effects. I could continue on building a blacklist, but I do not want to enumerate what is unsafe. I want to know what is safe, but I can not find any documentation of this.
UPDATE: In my example JavaScript from the victim site was executed on the attacker's site, not the other way around, which would have been Cross Site Scripting.
Another example is images, where any other site can read the width and height, but I don't think they can read the content, but they can display it.
A third example is that everything without an X-Frame-Options header can be loaded into an iframe, and from there it is possible to steal the data by tricking the user into doing drag-and-drop or copy-and-paste.
The key point of Cross Site Attack is to ensure that your input from user which is going to be displayed, is legal, not containing some scripts. You may stop it at the beginning.
If for example my sensitive data is in JavaScript format, the other site can include it in a script tag
Yep! So don't put it in JavaScript/JSONP format.
The usual fix for passing back JSON or JS code is to put something unexecutable at the front to cause a syntax error or a hang (for(;;); is popular). So including the resource as a <script> doesn't get the attacker anywhere. When you access it from your own site you can fetch it with an XMLHttpRequest and chop off the prefix before evaluating it.
(A workaround that doesn't work is checking window.location in the returned script: when you're being included in an attacker's page they have control of the JavaScript environment and could sabotage the built-in objects to do unexpected things.)
Since I did not get the answer I was looking for here, I asked in another forum an got the answer. It is here:
https://groups.google.com/forum/?fromgroups=#!topic/mozilla.dev.security/9U6HTOh-p4g
I also found this page which answers my question:
http://code.google.com/p/browsersec/wiki/Part2#Life_outside_same-origin_rules
First of all like superpdm states, design your app from the ground up to ensure that either the sensitive information is not stored on the client side in the first place or that it is unintelligible to a malicious users.
Additionally, for items of data you don't have much control over, you can take advantage of inbuilt HTTP controls like HttpOnly that tries to ensure that client-side scripts will not have access to cookies like your session token and so forth. Setting httpOnly on your cookies will go a long way to ensure malicious vbscripts, javascripts etc will not read or modify your client-side tokens.
I think some confusion is still in our web-security knowledge world. You are afraid of Cross Site Request Forgery, and yet describing and looking for solution to Cross Site Scripting.
Cross Site Scripting is a vulnerability that allows malicious person to inject some unwanted content into your site. It may be some text, but it also may be some JS code or VB or Java Applet (I mentioned applets because they can be used to circumvent protection provided by the httpOnly flag). And thus if your aware user clicks on the malicious link he may get his data stolen. It depends on amount of sensitive data presented to the user. Clicking on a link is not only attack vector for XSS attack, If you present to users unfiltered contents provided by other users, someone may also inject some evil code and do some damage. He does not need to steal someone's cookie to get what he wants. And it has notnig to do with visiting other site while still being logged to your app. I recommend:XSS
Cross Site Request Forgery is a vulnerability that allows someone to construct specially crafted form and present it to Logged in user, user after submitting this form may execute operation in your app that he didin't intended. Operation may be transfer, password change, or user add. And this is the threat you are worried about, if user holds session with your app and visits site with such form which gets auto-submited with JS such request gets authenticated, and operation executed. And httpOnly will not protect from it because attacker does not need to access sessionId stored in cookies. I recommend: CSRF

XSRF protection GET .net mvc

I have a site which will show sensitive information. I am using Anti Forgery Tokens etc to protect against XSRF in POSTS. However I am worried about someone being able to view sensitive info from a GET. What is the recommended practice for protecting read only data sent via a GET in .Net MVC 2?
If you are sure that GET requests are read-only, then you have nothing to worry from XSRF. Its not possible to steal information from another website using just XSRF, and so you don't need to protect urls via a token. In fact, using tokens in the URL is going to make it impossible to use bookmarks.
Having said that, you should be 100% sure there are no XSS vulnerabilities in your app. If there are, an attacker doesn't need to bother with XSRF and unpredictable tokens.
The XSRF protection on POST data (using tokens like you said) should work on GET data as well. From a hacker's point of view a GET forgery is much easier than POST forgery (at the first you only post a link, at the second you need to point to a malware website with hidden iframe and autosubmit forms), but both of them fail if tokens are checked.
Example:
posting a link like this:
www.domain.tld/page.aspx?get=data&token=token_given_to_hacker
shouldn't return anything, or just an error for those who got other tokens. This way no sensitive action is made for the wrong people.
This is xsrf, with this you can't steal information, but make others submit forms and take action which result only the hackers know. For example:
Changing email, on an email form, to the email of the hacker. Let's assume you have a GET form, with 1 field: the new email (for the sake of simplicity). When submitted the URL looks like this:
www.domain.tld/page.aspx?email=myemail#otherdomain.tld
Now, if a hacker posts a link on your forum with the URL:
www.domain.tld/page.aspx?email=hackers_email#yetotherdomain.tld
Everyone who clicks on it, will get a new email, of the hackers. But if you put a token there, and you'll check it every time, the action will be taken only for those who's the same token was given on page request, in this case the link will work only for the user who posted it, and no one else.
You could also protect sensitive forms, like changing email, password and so on with a password field. Note, that captcha is not much of a help here.

XSS as attack vector even if XSS data not stored?

I have a question about XSS
Can forms be used as a vector for XSS even if the data is not stored in the database and used at a later point?
i.e. in php the code would be this:
<form input="text" value="<?= #$_POST['my_field'] ?>" name='my_field'>
Showing an alert box (demonstrate that JS can be run) on your own browser is trivial with the code above. But is this exploitable across browsers as well?
The only scenario I see is where you trick someone into visiting a certain page, i.e. a combination of CSRF and XSS.
"Stored in a database and used at a later point": the scenario I understand about CSS is where you're able to post data to a site that runs JavaScript and is shown on a page in a browser that has greater/different privileges than your own.
But, to be clear, this is not wat I'm talking about above.
Yes, it's still an attack vector.
What you need to consider is:
Can an authenticated user be tricked into viewing this page with maliciously-crafted data?
The answer is this case is yes (assuming you have authenticated users). Because it's possible to direct someone to your site and pass in malicious variables to that field.
Yeah, it's still an attack vector, although impact is more situational.
Here's a contrived scenario that expands on previous answers if the form requires authentication to reach (and is easier if the site doesn't care if forms are submitted via POST or GET):
1) Attacker uses CSRF to login the victim using the attacker's credentials (e.g. <iframe src=http://../login?id=...&pass=..."></iframe>). This way the attacker brings the form to the victim and it doesn't matter if the victim doesn't have an account.
2) Attacker uses another CSRF to execute XSS against the form, which asks the victim for some credentials, etc. (This is where some convincing social engineering needs to occurr or the attacker has some useful JavaScript to use within the browser's Same Origin for the site.)
Another contrived scenario in which the vulnerable form performs some important action, like transfer money between accounts:
0) Vulnerable form uses hidden form fields with random values to prevent CSRF. The attacker doesn't know what the values are and can't set up a proper attack.
1) Attacker creates a CSRF payload that includes JavaScript to read a form's random csrf tokens (i.e. pull them from the browser's DOM).
2) Victim logs into site.
3) Attacker lures victim to CSRF payload, CSRF bootstraps the form request with the correct csrf tokens because it's executing in the victim's browser, within the victim site's Same Origin, and using the victim's auth session. The attacker doesn't need to know the csrf tokens, just be able to manipulate the form fields that store them.
4) Attacker benefits from having the victim submit the form -- no pop-ups or social engineering necessary aside from luring the victim to the CSRF payload, but the form needs to do something "useful" for the attacker.
i think what you are mean is, since User 2 cannot be showing previous data added by User 1, so can the XSS happen? So if User 1 hack the URL so that some $_GET params got displayed on the webpage as well (and then even, change it to a tinyurl), and spread this URL saying that it is really worthwhile to see this page, etc, then it might be possible.
So it is still better to escape all params when displaying the page.
That is absolutely a valid form of XSS. XSS comes in two forms - stored and reflected. Reflected is much more common, but stored has the potential to be more damaging. Reflected XSS is usually used as part of a social engineering attack. An attacker creates a URL like the following:
http://host.com/page.php?my_field=malicious_code
They will often shorten the URL with tinyutl or bit.ly, and get it out with the usual social engineering methods (email, message board, twitter, hijacked facebook accounts, etc.)

Resources