12

I want to store users' personal urls as plain text, encoded by htmlspecialchars().

Then I would retrieve this data and generate and display a link, as follows:

echo '<a href="'.$retrieved_string.'" target="_blank">';

And yet, even with encoded special chars and quotes, the href may not be safe, due to the potentially inserted javascript, example of a bad link:

javascript:alert(document.cookie);

So what I'm thinking is to strip up for a potential 'javascript' tag (before I do the special chars encode of course), as follows:

preg_replace('/^javascript:?/', '', $submitted_and_trimmed_input);

So let us sum it up altogether:

$input=htmlspecialchars(preg_replace('/^javascript:?/', '', trim($_POST['link'])),11,'UTF-8',true);
mysql_query("update users set link='".mysql_real_escape_string($input)."'");

//And retrieving:

$query=mysql_query("select link from users");
$a=mysql_fetch_assoc($query);
echo '<a href="'.$a['link'].'" target="_blank">';

Now the question is, would it be enough to an url link safe, or is there any other potential surprises I should be alert against?

EDIT:

I've read a bit about filter_var() and it seems to utterly fail in many ways. It doesn't validate international domains with unicode chars, then again the following string successfully passes the test:

http://example.com/"><script>alert(document.cookie)</script>
  • I mean common... that's just rediculous, there must be a better way
Anonymous
  • 4,494
  • 7
  • 56
  • 87
  • 2
    Stop using `mysql_*` functions. They're being deprecated. Instead use [PDO](http://php.net/manual/en/book.pdo.php) or [mysqli](http://php.net/manual/en/book.mysqli.php). If you're not sure which one to use, [read this SO article](http://stackoverflow.com/questions/13569/mysqli-or-pdo-what-are-the-pros-and-cons). – Matt Aug 02 '12 at 15:38
  • I mean they are deprecated, It's just about being cautious using them which I do. – Anonymous Aug 02 '12 at 15:39
  • PDO and mysqli have sanitization functionality. Why *wouldn't* you want to use them? – Matt Aug 02 '12 at 15:41
  • They aren't always supported as most of the systems are still written using the old ones. For any future projects I would consider implementing mysqli or pdo. – Anonymous Aug 02 '12 at 15:45
  • You make a valid point, but mysqli is supported in PHP 4.1; PDO as of 5.1. How old is the PHP on your server? – Matt Aug 02 '12 at 15:47
  • Oops, I didn't know that... It's actually 5.2 but it was initially written for SQL Server, it was a nightmare setting it up to work, and the only way I could make it work was using the old drivers with dynamic queries the same way. Then I rewrote it for Mysql... – Anonymous Aug 02 '12 at 15:58
  • In that case you might want to pencil in some time to refactor your system to use a more secure database library. :-) – Matt Aug 02 '12 at 16:01

2 Answers2

11

Try using filter_var()

filter_var('http://example.com', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED)
John Conde
  • 212,985
  • 98
  • 444
  • 485
  • So instead of example goes my link I guess? :) – Anonymous Aug 02 '12 at 15:37
  • Yep, that's all you need to do. :) – John Conde Aug 02 '12 at 15:39
  • 10
    I've read a bit about filter_var() and it seems to utterly fail in many ways. It doesn't validate international domains with unicode chars, then again the following string successfully passes the test: 'http://example.com/">' - I mean common... that's just rediculous – Anonymous Aug 02 '12 at 16:40
-2

This is how I'm gonna do it. It looks to me the best way is to prepend it with http:

$link=preg_replace('/^(http(s)?)?:?\/*/u','http$2://',trim($_POST['website']));

So even if a script gets there I couldn't care less. Then actually convert chars:

$link= htmlspecialchars($link, 11,'UTF-8',true);

That's it. No beating around the bush, and should be utf-8 compat also.

Anonymous
  • 4,494
  • 7
  • 56
  • 87
  • This does not work. You would need to pass `ENT_NOQUOTES` to `htmlspecialchars` to make it escape quotes. Your `'example.com/"> – Billy ONeal Aug 03 '12 at 00:51
  • Yes, really. Read the documentation: http://www.php.net/manual/en/function.htmlspecialchars.php . – Billy ONeal Aug 03 '12 at 01:06
  • ENT_NOQUOTES Will leave both double and single quotes unconverted. – Anonymous Aug 03 '12 at 01:06
  • Sorry, I misquoted the flag. It's ENT_QUOTES. The default leaves single quotes unconverted. – Billy ONeal Aug 03 '12 at 01:16
  • Erm, it isn't documented what ENT_QUOTES resolves to in terms of an integer. Relying on the specific value is just asking to turn into a security problem if the flag value changes in the future. As for testing everything, I'll test everything when you stop calling people retards for making careless errors. People make mistakes; deal with it. – Billy ONeal Aug 03 '12 at 06:19
  • 2
    @Anonymous: You are being rude. Please restrain yourself a little. We're here to help. http://stackoverflow.com/faq#etiquette – Jens Aug 03 '12 at 06:54