Reputation: 23
In my website ( server side is c# ) , I let users submit links like this:
<a href="$">link text</a>
Whatever they input will stay inside the "href" attribute only. i want to prevent XSS through the "href" URL.
Right now i check if it's a valid url the c# object URI.
My questions are:
For example how can i prevent XSS phishing attack of a valid url as: "http://xss.rocks/xss.css"
Upvotes: 2
Views: 4839
Reputation: 3573
To answer your question - validating as System.Uri is not enough. My approach to the problem:
&
) if detected - reject the urlAt this point the url could still be something like javascript:alert(1)
- the browsers will accept the :
while WebUtility.HtmlDecode
fails because of missing semicolon so:
Here is the code.
private static readonly string[] acceptedSchemes = { Uri.UriSchemeHttp, Uri.UriSchemeHttps, Uri.UriSchemeMailto, Uri.UriSchemeFile };
private static readonly char[] forbiddenHrefChars = { '"', '\'', '`', (char)10, (char)13 };
private static readonly char[] forbiddenBeforeQueryString = { ':', '&', '\\' }; // the colon may look surprising, but if we deal with a colon we expect something which parses as URI
/// <summary>
/// Returns true if the specified string is considered XSS safe href attribute value.
/// </summary>
public static bool IsSafeHref(string input)
{
if (input.Any(c => forbiddenHrefChars.Contains(c)))
return false;
// do not accept any entities
string href = WebUtility.HtmlDecode(input);
if (href != input)
return false;
// check if the scheme is valid, if specified
bool isUri = Uri.TryCreate(input, UriKind.Absolute, out Uri uri);
if (uri != null)
return acceptedSchemes.Contains(uri.Scheme ?? "");
int qsIdx = href.IndexOf('?');
string partBeforeQueryString = qsIdx < 0 ? href : href.Substring(0, qsIdx);
if (forbiddenBeforeQueryString.Any(c => partBeforeQueryString.Contains(c)))
return false;
return true;
}
I believe it should not allow any way to switch the context of the URL to execute as javascript. Please let me know if you find a way to break it.
Upvotes: 0
Reputation: 7140
Validating as a URI is a good start. After that, verify the scheme
is a white-listed option such as http
/https
. After that, make sure that you encode it before outputting it (see OWASP link). Basically, you do exactly what you do for any html attribute encoding, except you also need to be aware of malicious schemes.
Things to look out for: javascript:alert(1);
(validate scheme), https://example.com?xss=" onclick=alert(1);//
(escape output).
See:
As for the second part of your question, once the user clicks the link and goes to the new site, it isn't XSS on your site anymore. Letting users add any URL can still be dangerous, even if it isn't an XSS vulnerability though. They can still link to malicious sites, illegal content, etc. For those, you can perhaps validate against a site reputation API like Google provides, but even that is not bulletproof.
Upvotes: 1