I need to sanitize an unsafe URL on my site. Trying to use the DomSanitizer's sanitize method, but am getting unexpected results. The docs seem clear that some kind of sanitization should be taking place for the method sanitize(), but I'm not seeing anything. "The implementation is responsible to make sure that the value can definitely be safely used in the given context."
Why would sanitizing a safe url to RESOURCE_URL throw an error?
Why would sanitizing an unsafe url to URL not sanitize the string?
Bonus: Why do I see some doing bypassSecurityTrustUrl( sanitize() ) ? Shouldn't the sanitize method make a string safe?
safeURL:string = "android.com";
unsafeURL:string = "android.com?param=<script>alert('xss!');</script>";
outputURL:string | null;
constructor(private sanitizer: DomSanitizer) {
this.outputURL = sanitizer.sanitize(SecurityContext.URL, this.safeURL);
console.log(this.outputURL) //android.com
this.outputURL = sanitizer.sanitize(SecurityContext.RESOURCE_URL, this.safeURL);
console.log(this.outputURL) //Error: unsafe value used in a resource URL context
this.outputURL = sanitizer.sanitize(SecurityContext.URL, this.unsafeURL);
console.log(this.outputURL) //android.com?param=<script>alert('xss!');</script>
this.outputURL = sanitizer.sanitize(SecurityContext.RESOURCE_URL, this.unsafeURL);
console.log(this.outputURL) //Error: unsafe value used in a resource URL context
}
From docs:
Sanitization is the inspection of an untrusted value, turning it into a value that's safe to insert into the DOM. In many cases, sanitization doesn't change a value at all. Sanitization depends on context: a value that's harmless in CSS is potentially dangerous in a URL.
It is important to note that in many cases sanitization doesn't change a value at all; and also what's safe or unsafe depends upon the context.
Why would sanitizing a safe url to RESOURCE_URL throw an error?
It's important to understand difference between URL and RESOURCE_URL.
Resource URLs could be those containing Base64 data or the html elements <script src>
or <iframe src>
which do load some resources(executable code). Such data is an arbitrary data and there is no way for the framework to know if such Resource URLs are safe and hence sanitizing resource URLs isn't possible.
Calling sanitize
with SecurityContext.RESOURCE_URL
context, always throws an error unless the value is marked as trusted. It is a way of framework telling us that we as application developers need to ensure that the Resource URL is safe to use.
It could be that we are loading resources from our own server and hence we know that it's safe to use, in such cases we can call bypassSecurityTrustResourceUrl()
to tell Angular that we trust the Resource URL and Angular will then not throw error for those Resource URL. Calling bypassSecurityTrustResourceUrl()
with the URL that might contain untrusted user data may result in security risks within our application.
Why would sanitizing an unsafe url to URL not sanitize the string?
The string you are using is not unsafe in the URL context i.e when using it as
<img [src]="unsafeURL">
or<a [href]="unsafeURL">Link</a>
But the same string is unsafe when used in SecurityContext.HTML
context i.e maybe when used within [innerHTML]
.
unsafeHTML = "android.com?param=<script>alert('xss!');</script>";
// The value is stripped in HTML context
this.outputURL = sanitizer.sanitize(SecurityContext.HTML, this.unsafeHTML);
console.log(this.outputURL) // android.com?param=
In SecurityContext.URL
context the string value is returned as it is when it matches the SAFE_URL_PATTERN or DATA_URL_PATTERN regex.
An example of unsafe url:
unsafeURL = "javascript:alert('Lottery!')";
this.outputURL = sanitizer.sanitize(SecurityContext.URL, this.unsafeURL);
console.log(this.outputURL) //unsafe:javascript:alert('Lottery!') */
I would also recommend you to go through Sanitization and security contexts