I'm trying to learn how to use Laravel Sanctum authentication. When I send GET https://localhost/sanctum/csrf-cookie I get the following CSRF cookies:
XSRF-TOKEN=eyJpdiI6Inhvb0FDVXdHZDU5QzBqQTNKaWNxTUE9PSIsInZhbHVlIjoiSXNudjNiNE9xbmtNVWdsQ0l2SDRyYUNPQXIrTGJLb2ZMVDc2NWttenZGY0NkcDRvQzFVQlZOMDRlNFdTOHJaNiIsIm1hYyI6ImY0Y2M2YzZiZWIxYWVmZTRmMWI5NWRhNTBhN2JmM2VjNGExYjU0MGYwYWVmYTE4ODQxM2I0YTFlMWVjZTVhMDkifQ%3D%3D;
You can notice the strange %3D%3D at the end of the token. These characters also added for my laravel_session cookie.
When I then send back a request with this exact token in the header X-XSRF-TOKEN, I'm getting token mismatch error. When I remove the characters - all works. I wonder where's these characters came from and how can I remove them.
UPD: since those were encoded URL characters, when I decoded them and put '==' instead at the end of X-XSRF-TOKEN, that seems to be working. Still, it's strange why it worked before when I just removed the characters from the query manually.
Yeah this stands for the = symbol which is part of your base64'ed CSRF token. I'd guess it only works when you remove it because the = symbol is the special padding character. In a very high level they just pad the string out to the proper length.
As you already know, = becomes %3D when it is url encoded.
Usually when you encounter a string with lot of numbers and characters in random order and it ends with == there is a very high probability that it is encoded in base64.
= is added (at the end of the string) as padding to match a specific number of characters in a string. You can read more about it in this answer.
To answer your question, I will try decoding the given token with and without == at the end, I'll use this online decoder, so you can try it at your end aswell.
With ==:
{"iv":"xooACUwGd59C0jA3JicqMA==","value":"Isnv3b4OqnkMUglCIvH4raCOAr+LbKofLT765kmzvFcCdp4oC1UBVN04e4WS8rZ6","mac":"f4cc6c6beb1aefe4f1b95da50a7bf3ec4a1b540f0aefa188413b4a1e1ece5a09"}
Without ==:
{"iv":"xooACUwGd59C0jA3JicqMA==","value":"Isnv3b4OqnkMUglCIvH4raCOAr+LbKofLT765kmzvFcCdp4oC1UBVN04e4WS8rZ6","mac":"f4cc6c6beb1aefe4f1b95da50a7bf3ec4a1b540f0aefa188413b4a1e1ece5a09"}
They are same.
It works because they (=) are just padding and they DO NOT contain any information.
I am no laravel expert but, I am guessing the reason it doesn't work with %3D is because it is not decoding the url.
Related
I'm setting up a PHP email tracking system that uses url parameters to track link click throughs. Something like:
www.example.com?trackToken=10
I'm looking for a simple PHP encode / decode function I can put in place that will take a number (in this case 10) and convert in to strictly to number and letters. something like:
www.example.com?trackToken=7aj8nG93nDpw9M9Nk1
I have found several variations of encrypt / decrypt functions using mcrypt. However, the encrypted output always ends up containing strange characters. These strange characters make it hard for my email messages to be sent/delivered.
Does anyone know of a good encrypt function that only outputs numbers 0-9 and letters a-z or A-Z? Additionally, I'm looking for a decrypt function to complement the encrypt function so I can actually use it.
I'm not looking for something super secure here. Just a way to mask the actual tracking token so the user can't change it on their own.
Base64 should be fine in any modern system - and any system handling email in PHP fits the definition of "modern". There is absolutely no reason I can think of to limit to just alphanumerics. The only catch is that as a URL parameter you don't want to have a '+' or '/' in the string. There is base64url to solve this problem but that doesn't have a standard PHP function. You can easily replicate that by using base64_encode() and str_replace() and to decode str_replace followed by base64_decode():
$coded = str_replace('+','-',str_replace('/','_',base64_encode($original)));
$original = base64_decode(str_replace('_','/',str_replace('-','+',$coded)));
I am trying to send a url like this for search data
http://localhost/project/search/text:75%
I am getting 400 - Bad Request error in here.
I even tried replacing percentage with %25. But it didn't worked. How should I send the search data containing percentage?
In URLs, the % percent character is reserved for character encoding.
Usually to represent a % character you can use %25, but as you have already tried this and that it doesn't work for you, you should instead use PHP's urlencode function like so:
$url=urlencode("text:%75");
The same issue occurs with :, this therefore prevents the same issue with this character also (which for reference is %3A).
Partially from this question.
I'm working on a reset password function that matches hashes to allow for the user to reset. The only trouble is the hash that was created cannot be passed over URL without breaking the page. For example, my hash is this:
http://localhost/users/changeResetPassword/e0b4ab1d2cdc5742c7b5f72ef6c2935dadfe458dc275b7419d9f1ac66461aa20%0F5%3A%C6%5C%26%2A%E4%D5%ACA%94%ADV%BF%EB%CAz%97O%1F%7D%F0h~%E3-.%FF%B4z%5E%1AQ%B8%8Ca%BC500%2A%EC%7B%FA%AF8%E3%2A%7F%BA%A4y%03%AE%29%94%09%26%9E%29e%E5%DEn%1At%C1%EC%F7%D4x%EAvlA%BE%5B%0D%CF
All of these % seem to break the page, because I get this error:
Object not found!
The requested URL was not found on this server. If you entered the URL manually please check your spelling and try again.
If I take away everything up to the last % and try it again, the page loads fine. It's just some characters in the URL seem to bug everything out:
http://localhost/users/changeResetPassword/e0b4ab1d2cdc5742c7b5f72ef6c2935dadfe458dc275b7419d9f1ac66461aa20
This loads fine, so I know it's just a URL problem. Any ideas?
Base64 encode the hash and pass it along, then decode when received. Cake URI parsing likely breaks because it'll try to interpret those %xx as html encoded values but it does not appear that is what they are since you have stuff like %03 and from the link: "The ASCII device control characters %00-%1f were originally designed to control hardware devices. Control characters have nothing to do inside a URL"
With regards to ndm's comment indicating you may additionally need to URL encode the base64 string since base64 can contain the characters + = / I'd recommend you also look at url encoded forward slash is breaking url to see why simply encoding the problematic characters might also be problematic. If the current solution of passing unencoded base64 strings is not causing any issues with your rewrite rules I would recommend you keep it as it.
Using the same (basic) code from here but switching to MCRYPT_RIJNDAEL_128, I'm now getting the correct data out of php mcrypt_decrypt, except in certain circumstances, it's padding out the end of my message a newline with seemingly random binary characters.
The following, for example, came back from a request to decrypt:
{"messageData":{"identity":"test","msg_id":0,"token":"fakeToken58586"},"messageName":"fetchSavedData_request"}\n\b\b\b\b\b\b\b\b
I would think this is a padding issue, but even if I pad out my string to the correct length, I occasionally get garbage, and strings that would normally need to be padded, do occasionally come back correct.
What's going on here?
As #Jack pointed out in the comments, this is apparently a common problem. The code here works to remove control characters at the end of encrypted data.
Reproduced here for posterity:
$data = preg_replace( "/\p{Cc}*$/u", "", $data);
My web application communicates with the server over JSON protocol. Before sending each JSON message from the web application, I run a hmac-sha1 function on it (on already encoded object) and insert the resulting HMAC into the header of JSON request.
On server side, I decode JSON message with PHP, extract the HMAC, unset() the HMAC from the object and then encode the object back into JSON and create a HMAC of it.
The HMACs match as long as I don't use characters like "ž, š, č". When I use those characters in the message, the HMACs don't match anymore.
In the web application I'm using jQuery.post() to transmit the already encoded JSON string.
If I send the data I got from the web application back to it in the JSON encoded reply, the application will display "ž, č, š" just nicely.
How can I make the HMACs match?
UPDATE:
This is only a problem on latest version of Firefox and Opera. It works fine on IE8 and Chrome. On the former browsers, the JSON string (before it is sent) is:
{"body":[{"name":"Žiga Kraljevič","email":"test#email.com","password":"secretpass"}],"header":{"apiID":"person-27jhfa83ha-js84sjj18dasjd","hmac":"e4259d6ef8f477c020d644409cc16dd9c42301e8"}}
While on the latter browsers (IE8 and Chrome, where it works) is the following:
{"body":[{"name":"\u017diga Kraljevi\u010d","email":"test#email.com","password":"secretpass"}],"header":{"apiID":"person-27jhfa83ha-js84sjj18dasjd","hmac":"e4e9e2d0d8d11728a2b4329ad6dacdb9409b1de1"}}
You're probably running into multiple issues. One of them may well be that the character encoding being used on the client is different from that being used on the server, worth ensuring that they're the same (more about character encoding in Joel's excellent essay). Another may well be that there are multiple correct ways to encode things. The encoders may well be using different ways. For instance, you can encode a " within a string as either \" or \u0022. Both are valid, and they're equivalent, but the hashes won't match. Similarly, I'm a bit surprised you're not running into more trouble when not using accented characters, for instance with whitespace.
What is your hmac-sha1 function, where's it from? If it is taking a JSON String as input then there's an implicit encode-to-bytes step going on here because SHA1 operates on bytes, not UTF-16 code units like JS String.
I would suspect that your JS function is using a “one code unit n per byte n” type of encoding, for easy calculation with tools like getCharCodeAt. This is effectively the same as if the character string input had been encoded to ISO-8859-1. Whereas if you are using encodeURIComponent or posting the raw characters via XMLHttpRequest, the implicit encoding there is UTF-8.
You could convert the String to UTF-8-bytes-stored-as-code-units format for the JS hmac-sha1 function, that might make it match PHP. There's a sneaky idiom to do this:
var utf8= unescape(encodeURIComponent(s));
When POSTing JSON I base64 and urlencode it anyway
URL-encoding should be enough (with encodeURIComponent, not escape which is the wrong thing for absolutely everything except the reverse step of the UTF-8-conversion trick above).
BTW, what's the purpose of this? You do know it doesn't in any way secure the connection between the browser and the server, yeah?
Edit:
I'm using jssha.sourceforge.net for sha1-hmac. In PHP I'm using hash_hmac.
Works for me:
var data= '\u017E, \u010D, \u0161'; // 'ž, č, š' in a Unucode string
var utf8bytes= unescape(encodeURIComponent(data));
var hmac= new jsSHA(utf8bytes).getHMAC('foo', 'ASCII', 'SHA-1', 'HEX');
alert(hmac); // 5d15f0b9...
var form= 'message='+encodeURIComponent(data)+'&hmac='+encodeURIComponent(hmac);
xmlhttprequest.send(form);
...
$utf8bytes= $_POST['message']; // "\xc5\xbe, \xc4\x8d, \xc5\xa1"
// which is 'ž, č, š' as UTF-8 in byte string
$hmac= hash_hmac('sha1', $utf8bytes, 'foo');
echo $hmac; // 5d15f0b9...
echo strtolower($hmac)===strtolower($_POST['hmac']); // true
This uses the binary ('ASCII' to jsSHA) key foo. If you are using a binary key with non-ASCII characters in it, you would have to make sure that those are properly encoded too, in the same way as the data.
The key for HMAC is a shared secret between the server and the client, which has been previously exchanged over a secure connection.
It's not only the key you'd have to send over a secure connection, but the entire page and all scripts in it. Otherwise a man in the middle attack could sabotage your scripts on the way to the browser to replace them with a version that used the secret key to sign bogus messages. If you've got an HTTPS server for all this stuff, fine. I'm not sure what the HMAC would be doing in that case though, it seems a bit involved for an anti-XSRF scheme.