-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[wip] adding rel=noopener for link_to when target=blank_ #25548
Conversation
Thanks for the pull request, and welcome! The Rails team is excited to review your changes, and you should hear from @matthewd (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
this PR is WIP currently because I wanna ask guys about API for this case. if you give string url, it seems no way to pass # how to opt-out from adding `rel=noopener` ?
link_to("Hello", "http://www.example.com", target: "_blank")
<a target="_blank" rel="noopener" href="http://www.example.com">Hello</a> because current # http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
link_to(body, url, html_options = {}) ## pattern A (NO URL_OPTIONS !!!)
link_to(body, url_options = {}, html_options = {}) ## pattern B
link_to(options = {}, html_options = {}) do ## pattern C
end
link_to(url, html_options = {}) do ## pattern D (NO URL_OPTIONS !!!)
end I think we have these options.
If I missed something for solve this problem, please mention me. Jxck |
end | ||
|
||
def target_blank?(html_options) | ||
html_options['target'] && html_options['target'].include?('_blank') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the problem noopener solves is present no matter the value of the target
attribute. For example, as best I can tell, target="foo"
causes the problem just like target="_blank"
. So perhaps the check here should just be for whether the target
attribute has any value.
(Side note: Using values other than _blank
for target
used to be used for opening the link in a frame with the matching name. I'm not sure if it has any practical use now, but it still works to open a new tab, at least in Chrome.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@LouieGeetoo |
# but you can disable <tt>rel="noopener"</tt> with using <tt>opener: true</tt>. | ||
# | ||
# link = link_to("Hello", "http://www.example.com", target: "_blank") | ||
# # => <a target="_blank" rel="noopener" href="http://www.example.com">Hello</a> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this example have opener true like: link = link_to("Hello", "http://www.example.com", target: "_blank", opener: true)
? Right now this example is the same as the first example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my mistake, I'll fix it.
@eileencodes |
@Jxck: Regarding the API question: I'm no authority on this (I only happened upon this issue because I was looking into the whole noopener problem overall), but would it make sense to make it an option within If the developer is explicitly setting Or maybe there shouldn't be an easy way to override it, since it's a security concern and we can perhaps assume that 99.9% of users will want it. Of course, I'm not sure whether either of those assumptions matches the Rails way of doing things. |
@LouieGeetoo in that case, how this will work ? link = link_to("Hello", url_hash, { target: "_blank", rel: "noreferrer" })
# 1, <a target="_blank" rel="noreferrer" href="/">Hello</a>
# 2, <a target="_blank" rel="noreferrer noopener" href="/">Hello</a> from point of motivation to adding this feature, I expect 2. if this should be result to 1, developer always care about adding noopener by themself every link_to which has another rel option. but it's seems frequent, so merit of this feature will decrease. totally my point of view, opting-out from noopener should be url_options which is option for link_to behavior, not to html_option which is directory affect to html attributes. |
This seems like a good security improvement, would it be possible to backport to 5.0.x or is this considered too much of a new feature/breaking change for that? |
Firefox does not support the I understand that this could be an issue because referrer will not be sent so could we propose this as a Rails option? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not working if "_blank" is a symbol: target: :_blank
@@ -556,10 +570,27 @@ def current_page?(options) | |||
end | |||
|
|||
private | |||
def default_noopener(rel) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Breaks if rel
already have a symbol (rel: :nofollow
).
could be replaced by something like that:
rel.to_s.split(' ').push('noopener').uniq
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you update the PR with the proposed changes and add a CHANGELOG entry?
Other than that I like the idea. Thank you so much for taking your time to improve the security of the framework.
@@ -98,6 +98,10 @@ def _filtered_referrer # :nodoc: | |||
# the link. The drivers each provide mechanisms for listening for the | |||
# completion of the Ajax request and performing JavaScript operations once | |||
# they're complete | |||
# * <tt>opener: false</tt> - If link has <tt>target="blank_"</tt> attribute, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be _blank
# * <tt>opener: false</tt> - If link has <tt>target="blank_"</tt> attribute, | ||
# generated html has <tt>rel="noopener"</tt> by default for avoid touching <tt>window.opener</tt> | ||
# from opened tab. If this option is <tt>true</tt>, it will remove <tt>rel="noopener"</tt> | ||
# from html even if link has <tt>target="blank_"</tt> attribute. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be _blank
@@ -556,10 +570,27 @@ def current_page?(options) | |||
end | |||
|
|||
private | |||
def default_noopener(rel) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@rafaelfranca @jvenezia @connorshea |
Would not |
@rafaelfranca which you mean 3 or 4 ? on (#25548 (comment)) I'll paste the pattern and choice again. patternswe are talking about A to C # http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
link_to(body, url, html_options = {}) ## pattern A (NO URL_OPTIONS !!!)
link_to(body, url_options = {}, html_options = {}) ## pattern B
link_to(options = {}, html_options = {}) do ## pattern C
end
link_to(url, html_options = {}) do ## pattern D (NO URL_OPTIONS !!!)
end choices
if you mean 3one more extra option for noopener ( if you mean 4adding url_options to end of A, D arguments |
I mean taking |
humm, I think I can't agree that. |
We can always filter the options before encoding to HTML attributes. I still think that is the best way to proceed. |
again
|
I'm somewhat concerned about us mutilating a |
@matthewd should we give a security warning instead of overwriting it if its already been defined? |
Yeah, that may happen but we can detect if rel was explicitly set and not apply
You just remove |
@rafaelfranca I think the concern is that currently all options in the EDIT: Actually that's incorrect, we already have some options that do not map directly. |
That is not a concern in my option |
|
no, I'm asking is if we add which we should out ?
or user point of view, |
Let's not care about future of HTML, if they add a |
everytime, that cause the breaking the web isn't it ? |
@Jxck I agree with the concern, but I think that's a discussion for a different thread. |
@connorshea which thread should we do that ?? (I'm talking about this issue) |
It is not breaking anything because there is nothing to break right now. There is no opener attribute in the HTML spec and it may not ever exist, if it exist we can deal with it when we need to. |
Ok, back to constructive discussion, could you make the changes that were requested? Otherwise I'll do myself. |
standard case of you thought cause like this. |
Ok. I'm out of this discussion. @matthewd feel free to merge it if you agree. Otherwise I'll close this in the next rails-bot iteration. |
@rafaelfranca @matthewd I found another choice. I heard that in that case, only other consider is so wrap them all |
No need to wait for the bot. |
or choice with small breaking change is to add this mean, someone who has contents with depend on opener should update their contents when update rails with fixing contents which depend on opener seems so few. |
@rafaelfranca @matthewd So do you plan to do this yourself? I think this feature is a real help for Rails security. I made a gem adding this feature, i'll be using it in the meantime. https://github.com/jvenezia/safe_target_blank link_to 'Safe', 'safe.io', taget: :_blank
#=> '<a target="_blank" rel="noopener noreferrer" href="safe.io">Safe</a>'
link_to 'Safe', 'safe.io', taget: :_blank, referrer: true
#=> '<a target="_blank" rel="noopener" href="safe.io">Safe</a>' |
I'm already discussed on ML here
https://groups.google.com/d/topic/rubyonrails-core/BPGwQXKWsws/discussion
copy are on Summary
Summary
link with target=blank_ will cause some kind of phishing attack known as tabnabbing.
detail of this attacks are described below.
this is caused by
window.opener
of JavaScript API, and it will prevent byrel=noopener
new API.so I propose adding this attribute to
link_to
when it giventarget: "_blank"
.here is
noopener
spec.https://html.spec.whatwg.org/multipage/semantics.html#link-type-noopener
currently implemented by chrome/opera.
http://caniuse.com/#search=noopener
noreferrer
is considered altenative ofnoopener
for older browser.but this cause not to send referrer to server, so it'll cause breakin change for some apps.
noopener
is no side effect for apps, without usingwindow.opener
ofcourse.API Change
basically
rel=noopener
will add when html option hastarget=_blank
by defaultyou can opt out to adding
rel=noopener
withopener: true
option.thanks
Jxck