5

Considering the following link_to example:

link_to "Personal Website", @user.website

How can I protect it against XSS attack. User table is in an external DB, so I cannot trust it. I have tried different approaches using sanitize and h but when I replace in my local DB user website by javascript:alert('XSS'), javascript is still being executed when I click on the link.

Thanks in advance,

Gabor Lengyel
  • 14,129
  • 4
  • 32
  • 59
smndiaye
  • 438
  • 7
  • 13

1 Answers1

2

You can remove "javascript:" in the controller. That's ugly but works, with some caveats (browsers are awesome in what exactly they may accept as "javascript:"). This is not a very strong control.

You can add "http://" (or "https://") statically to the link href, and strip that from your user input. As "javascript:" only works if it's at the first character of an href, statically adding http:// as the beginning mitigates XSS.

You can also use the Content-Security-Policy header to prevent inline Javascript from being run. This has implications on how you can structure your code, and is not supported in all browsers, but when it is suported, it's an excellent control.

As always, implementing multiple layers of defense (multiple of the above) will make your application more robust and secure against attacks.

Gabor Lengyel
  • 14,129
  • 4
  • 32
  • 59
  • Thanks for your answer. – smndiaye Nov 04 '16 at 00:30
  • My work around is your first suggestion. I am using brakeman and it is warning about a `unsafe model attribute in link_to href`. So I used a `get_user_url` method in my helper where I handle necessary controls. Brakeman is not warning about XSS attack anymore and at least `javascript:` is not being executed. But as you said it is a bit ugly, that's why I thought there might be a more elegant rails way of doing it. Thanks btw for the `Content-Security-Policy` suggestion. I took my time to dig a bit more about HTTP response header and that was instructive. – smndiaye Nov 04 '16 at 00:45
  • instead of modifying data, you can also do the following: `@user.website.start_with("http") ? link_to("Personal Website", @user.website) : @user.website` – Yoav Epstein Oct 17 '22 at 15:29