-
Notifications
You must be signed in to change notification settings - Fork 1k
Translate directive should only render sanitized HTML when postCompile is off #993
Comments
Valid point. That's why we have http://angular-translate.github.io/docs/#/guide/19_security -- original cause is backwards compatibility to AJS 1.2 (no ngSanitize). |
Is it possible to configure it in such way that it uses $sanitize instead of doing Also I don't agree with the current strategy of: let's keep this serious security issue for backwards compatibility. I would rather see a major version bump with this listed as a breaking change, and maybe the possibility to turn it off. I'm afraid that otherwise many people will overlook this in the documentation, like I did. |
Ehm, this was introduced while AJS 1.2 was available as stable. There is no "strategy", it's simply not possible. Afaik there was no simple way to inject a non existing module.. ?
Again, a valid point. Default security should be as high as possible (https://www.owasp.org/index.php/Establish_secure_defaults). A |
Oh, ok. So you are open to fixing this properly, which means introducing a breaking change? I could see if I can find the time to implement this. Actually, I looked in the docs and it turns out that $sanitize has been available since 1.0. Using it has a drawback, though. Since ngSanitize is released as a separate module, people do have to include it manually. However, I do think this is worth is, because I agree with you that default security should be as high as possible. I hope you didn't take my comments as critique of the highly appreciated work you guys are doing on this module. I only meant to provide some constructive feedback. Btw, I quickly looked through the code. It looks like that when you specify 'escape' only the values are sanitized, and not the translation texts themselves. I think it would be best to also sanitize the texts. |
You can make a proposal, but we will not make such a breaking change in a minor release. By definition this have to be |
Said this, I'm open for a breaking change release (aka 3.0.0), but this will probably take some time... |
fyi, I've opened #995 starting the topic about breaking changes... |
Thanks! I will look into this issue and make a proposal about how we should fix it. Hopefully I will also find the time to actually implement it, as soon as we agree on how it should be done. |
The actual plan was to extract the "strategies" as dedicated "plugins" (easiest way would be a simple function via config or even a module aka component/service) allowing to share them with all kinds of interpolators. Said this, this was the idea. But was not realized until now. |
I am willing to implement this. My proposal would be to do it as follows:
@knalli what do you think? Does this sound like a good approach? |
@marklagendijk Thank you!
|
The idea I had was to have two kind of strategies:
The idea of the sanitizeTranslationStrategy is that it would be applied on the whole result, after interpolation. Was your idea to use one strategy both? This would be possible. We could just call the same sanitize function (belonging to the currently selected strategy) in both cases. This function should then check whether it got passed an object (-> params) or an string (-> whole translation), and act accordingly. This would also make it a non-breaking change, so it could already be released as part of 2.x. We could just add several strategies:
In 3.0 we would change to either @knalli let me know what you think. If you have suggestions for better names they are also welcome. Edit: by injecting |
Let's play with a demo set. Templates
Strategy: 0. noneObviously the bad one. No transformations. Strategy: 1. escapedEverything will be escaped. Actually the safest one, but obviously not always what you want.
Strategy: 2. escapedParametersSame as escaped? Strategy: 5. escapedTranslation
And now the additional two. I dont get why you say only 2 strategies. A small bit didn't get into my mind.. |
Your examples are correct. Only the sentence in I will work out the other two strategies: Templates
Stragey 3. sanitizedTranslationThis strategy calls
Stragey 4. sanitizedTranslationEscapedParametersThis strategy escapes parameters using the
|
Written before I had seen the fine difference between escapedParameters and -Translations. However, this is only valid in case you are not trusting the translation definition content itself. ;) Hm, okay, you are chaining the transformations actually. Perhaps we should split this down into
And the we define a chaining strategy like one of these
wdyt? |
Sounds good. Please see this gist. As a proposed implementation. The only problem with your proposed naming is that 'escaped' now has a new meaning. In the current version of angular-translate it means 'escapedParameters'. Do you think it is acceptable to change that without bumping the major version? Edit: after some refactoring iterations the code in the proposal is now quite clean. Please let me know what you think. |
I think we could solve the backwards compatibility issue by using slightly different names:
This way we could do: // Backwards compatibility for deprecated 'escaped'
sanitizeValueStrategies.escaped = sanitizeValueStrategies.escapeParameters; I must say that I slightly prefer this naming :). |
@marklagendijk : Yes, this looks good! I'm with you. In the final implementation I would think it is better to split the strategies (dedicated component functions?) and no hardcoded combinations (except a default one in the future). What happens in an AJS 1.2 environment with this one? https://gist.github.com/marklagendijk/55b98aba74f053752c19#file-default-interpolation-js-L78 I guess this will break everything (at least the running context). It would be okay to catch it gracefully and fallback to something else. We can cover this in the tests as they are running in each context (AJS 1.2, AJS 1.3, AJS 1.4). |
@knalli I was planning to refactor the strategies to its own
Do you agree with this approach? As for $sanitize, it has been available since Angular 1.x, but always as part of the separate ngSanitize module. This means that you have to add a reference to add a script reference to |
It's okay when the strategy won't works unless they have import ngSanitize. But I will only avoid a breaking change (i.e. new dependency in core). A good error message, but a working (with fallback) is okay. |
Should be covered when it will be ensured the lines are not running without explicit activation of the strategy in question. |
- Added $translateSanitization - Removed sanitization logic from interpolators, and implemented usage of $translateSanitization - Changed $translate to use $translateSanitizationProvider for setting the strategy
@knalli can you please review this commit? I took the following approach:
I think this approach is quite powerfull:
Let me know what you think. If you agree with this approach I will finish it, and make tests etc. |
I'll have a look later for details. |
- Added support for using multiple sanitization strategies, which will be executed as a chain. - Removed 'sanitize-escapeParameters' strategy. - Throw an error when an unknown strategy name is specified. Failing silently would be a security issue.
Ok, thanks! I added support for specifying a chain of strategies in this commit. |
@marklagendijk Well done! I've made some remarks (actually, you had already seen this). Looks good. For the PR please:
And finally: I want to add a warning about not using a safe strategy (via |
- Added sanitization.js in the Gruntfile. - Added methods for adding / removing strategies to the provider. - Changed isString checking in strategies to checking a 'mode' which is either 'params' or 'text' - Some refactoring and bugfixes. - Added documentation. - Restored $translateInterpolator.useSanitizeValueStrategy methods.
…ar-translate#993 - Added $translateSanitization - Removed sanitization logic from interpolators, and implemented usage of $translateSanitization - Changed $translate to use $translateSanitizationProvider for setting the strategy - Added support for using multiple sanitization strategies, which will be executed as a chain. - Throw an error when an unknown strategy name is specified. Failing silently would be a security issue. - Added methods for adding / removing strategies to $translateSanitizationProvider.
…ar-translate#993 - Added $translateSanitization - Removed sanitization logic from interpolators, and implemented usage of $translateSanitization - Changed $translate to use $translateSanitizationProvider for setting the strategy - Added support for using multiple sanitization strategies, which will be executed as a chain. - Throw an error when an unknown strategy name is specified. Failing silently would be a security issue. - Added methods for adding / removing strategies to $translateSanitizationProvider.
…ar-translate#993 - Added $translateSanitization - Removed sanitization logic from interpolators, and implemented usage of $translateSanitization - Changed $translate to use $translateSanitizationProvider for setting the strategy - Added support for using multiple sanitization strategies, which will be executed as a chain. - Throw an error when an unknown strategy name is specified. Failing silently would be a security issue. - Added methods for adding / removing strategies to $translateSanitizationProvider.
…ar-translate#993 - Added $translateSanitization - Removed sanitization logic from interpolators, and implemented usage of $translateSanitization - Changed $translate to use $translateSanitizationProvider for setting the strategy - Added support for using multiple sanitization strategies, which will be executed as a chain. - Throw an error when an unknown strategy name is specified. Failing silently would be a security issue. - Added methods for adding / removing strategies to $translateSanitizationProvider.
…ar-translate#993 - Added $translateSanitization - Removed sanitization logic from interpolators, and implemented usage of $translateSanitization - Changed $translate to use $translateSanitizationProvider for setting the strategy - Added support for using multiple sanitization strategies, which will be executed as a chain. - Throw an error when an unknown strategy name is specified. Failing silently would be a security issue. - Added methods for adding / removing strategies to $translateSanitizationProvider.
…ar-translate#993 - add new service $translateSanitization - remove sanitization logic from interpolators, and implemented usage within $translateSanitization - change $translate to use $translateSanitizationProvider for setting the strategy - add support for using multiple sanitization strategies, which will be executed as a chain. - throw an error when an unknown strategy name is specified. Failing silently would be a security issue. - add methods for adding / removing strategies to $translateSanitizationProvider. BREAKING CHANGE: You will get a warning message when using the default setting (not escaping the content). You can fix (and remove) this warning by explicit set a sanitization strategy within your config phase configuring $translateProvider. Even configuring the `null` mode will let the warning disapper. You are highly encouraged specifing any mode except `null` because of security concerns.
I had an issue with the sanitization as I was passing the whole $scope as parameter (the string to translate was dynamic and could contain different variables, so it felt easier/cleaner to just pass the scope than creating a brand new object with only the needed properties). When trying to sanitize the whole $scope, I end up with a stackoverflow exception. I guess it means we're trying to sanitize everything from the passed object, while maybe we could try to sanitize only the necessary properties, ie the ones that are actually used by the current string to translate. |
Well, both strategies try to either escape or sanitize all existing values in the object. That is not good, eventually
... which would means we have to pre-parse the string looking for each interpolation expression. We don't do this at the moment, as we are using standard AJS interpolation expressions. I'll file a new issue, feel free to contribute. Closing this here, we had introduced sanitization. |
The translate directive renders the text as HTML instead of text. Example:
Is rendered as:
This is a nice feature. However, when I found out about this feature I tested what would happen if I would put a script tag in the label. Turns out that it is rendered and the containing script executed. Example:
This is a serious security issue. The solution would be to make it work in the same way as ngBindHtml by using the $sanitize service. This will add a dependency on ngSanitize, but is the only way to do this properly.
The text was updated successfully, but these errors were encountered: