14

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,692
  • 8
  • 61
  • 91
  • 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
  • 217,595
  • 99
  • 455
  • 496
-1

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,692
  • 8
  • 61
  • 91
  • 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
  • will make `http://hello` from `hello` which is obviously not url – Fanky Jul 27 '22 at 13:43
  • The point is to prevent anything injecting into user's profile 'website' (other than links). For example this would prevent an injection of Javascript. If that url does not exist that's not our problem. – Anonymous Jul 29 '22 at 22:51