0
$token = base64_encode( openssl_random_pseudo_bytes(32));

<input type="hidden" name="csrf_token" value="<?=$token?>">

Do I need to escape the $token on output?

Danny Beckett
  • 20,529
  • 24
  • 107
  • 134
John
  • 2,900
  • 8
  • 36
  • 65

2 Answers2

2

There is no point in escaping base64 encoded data, by definition it won't have any control characters (or quotes etc.) inside.

Hazzit
  • 6,782
  • 1
  • 27
  • 46
  • It might have new lines in it. It could be a good idea to remove them. – Stephen Ostermiller Mar 03 '13 at 22:02
  • A base 64 encoded data should not contain new lines. Take a look here : http://en.wikipedia.org/wiki/Base64 – MatRt Mar 03 '13 at 22:03
  • @user1073122 actually, MIME's base64 can contain newlines: `MIME does not specify a fixed length for Base64-encoded lines, but it does specify a maximum line length of 76 characters. Additionally it specifies that any extra-alphabetic characters must be ignored by a compliant decoder, although most implementations use a CR/LF newline pair to delimit encoded lines.` Take a look here: http://en.wikipedia.org/wiki/Base64 – El Hocko Mar 03 '13 at 22:11
  • Of course it used to delimit the end of the data, but as pure data, it is useless. – MatRt Mar 03 '13 at 22:16
  • @user1073122 What are you trying to say? – John Mar 03 '13 at 22:27
  • I am trying to say that it not a general rule, it only a MIME rule, when you are using base64 in E-MAIL (in order to add image in your e-mail for example). In other case, this limitation does not exists. Example: when you are using base64 in CSS (to put the image content directly in the CSS) you don't have any length limitation. So it depend how the data will be used. In your use case, i would not add new line in the value of your input.. – MatRt Mar 03 '13 at 22:34
  • This discussion of newlines is irrelevant to the question discussed here for two reasons: it's only 32 bytes of data and he's encoding it, not decoding. So if he doesn't put newlines in by himself, none will come out. – Hazzit Mar 03 '13 at 22:47
0

Actually, you might. The problem lies in the fact that one of the base64 encoding characters, the one with index 62, is actually encoded by PHP as a plus character (+), and that plus might get URL-decoded as a space by the browser when sending it along (or rather, by something between the browser and the server - a proxy, a load balancer, a filter...).

Therefore, some data risks being encoded in a form that will then be decoded as a different string (and actually not be decoded at all, since space will break the base64 scheme).

Both modern Firefox and Chrome correctly encode that + into %2B (I just tested), and the standards seem to dictate that the + must always be encoded and base64 does not need further escaping but the problem arises in some cases (see URLs and plus signs ).

Rather than risking the token working 99.97% of the time (the 0.03% being the day you needed it the most, as Murphy rules), a simple workaround would be to convert the token to hexadecimal byte representation:

$token = bin2hex(openssl_random_pseudo_bytes(32));

<input type="hidden" name="csrf_token" value="<?=$token?>">
Community
  • 1
  • 1
LSerni
  • 55,617
  • 10
  • 65
  • 107
  • The base64_ will only be used on POST forms. – John Mar 03 '13 at 22:35
  • I know, and chances are that you won't need encoding there, ever (I tried with Firefox, Chrome and IE8+, through Squid and NginX, and they all work as they should). All the same, unless there's a specific reason for going base64, `bin2hex` and `hex2bin` remove the *chance* and give you a *guarantee*. I once encountered a base64 encoding trouble - it might have been a Django site? - where the "plus" sign bit me in the rear. It could be a difficult bug to track down, the csrf being random and all. At the very least, be aware of the possibility :-) – LSerni Mar 03 '13 at 23:35