Handling JSON POST request using PHP and SHA1 - php

So I am using a REST API, where the API issues a POST request to my server in JSON format. Following is the information it sends:
info: {
id: "9890dsds8",
number: 5,
amount: 33
},
sig: "8jhjbhb78979899h"
sig is a SHA1 signature of the info, this should be used to validate the post. For example, we can validate the info in Ruby with (as given in their example):
require 'json'
require 'cgi'
require 'digest/sha1'
key = "some_key"
params = CGI::parse(post_body)
digest = Digest::SHA1.hexdigest(params["info"]+key)
if digest == params["sig"]
# Valid signature
info = JSON.parse(params["info"])
# Respond with status code 200 and some unique_id
else
# Invalid signature. You should response with a non-200 response code.
end
The unique_id must be a string of UTF8 characters 50 characters in length or less and should be the only contents of the body of your response.
Though I am quite able to understand what's happening, I am not completely able to figure out everything. Mostly, may be because its in Ruby.
Can someone please help me on how to do this in PHP? I am not able to handle this JSON POST request in PHP. A PHP converted version of the snippet would be extremely appreciated. I am also not sure, how to deal with SHA1 aspects in PHP, any special knowledge required?
Thanks a lot!!

I assume that the API will populate the "response" variable in your POST array.
Then:
//Get the JSON string
$json_string = $_POST['response'];
//Decode JSON string to array
$decoded = json_decode($json_string);
//Calculate SHA1 (I am not sure how ruby is concatenating a string with an array, so I will just convert the array to string using implode).
$key = 'somekey';
$hash = sha1(implode("",$decoded['info']) . $key);
if($hash == $decoded['sig']){
//OK!
}else{
//Not OK!
}

Related

Unable to decode JWT tokens PHP

I tried to decode the given token with the code below. The key is supposed to be base64 encoded. However when I attempt to decode it tells me I have invalid signature. The token is generated from a system using Java and I have to decode it in PHP.
Token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyZXN1bHQiOiJzdWNjZWVkZWQiLCJpc3MiOiJ4eXoubmUuanAiLCJwcm9maWxlSWRlbnRpZmllciI6IioqKioqKio0NTY3IiwiZXhwIjoxNTk3MjAxNzQyLCJub25jZSI6ImRlNTRlODE3YmQ4NjM4MTI5ZWQ2ZDkxNDA1YTkwMTUyYWIzNTE4N2NkYWMxMDIxNmQ5NWI5NmUzYjgyMjAxNTFhZmU0ZDE4NWZlMzYzNTExNWMwNDFhOWY4OTNjMGZmMGFmZjFkYzBjODgyMDhmMjEwN2ZlMzk5Mzg3ZDMzZGMyZTllY2E5ODA0NDNmZjJiNjZiZDM1ZDk1YjAzY2ExMjIiLCJyZWZlcmVuY2VJZCI6IlRFU1QxMjM1ZjMzNTc3MzBlYjcxIn0.fvEsTg6OcCx2iBPMP-7e9AZtEviDqAEfTMZJib7UVQg
Decoding script
use \Firebase\JWT\JWT;
$encodedString = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyZXN1bHQiOiJzdWNjZWVkZWQiLCJpc3MiOiJ4eXoubmUuanAiLCJwcm9maWxlSWRlbnRpZmllciI6IioqKioqKio0NTY3IiwiZXhwIjoxNTk3MjAxNzQyLCJub25jZSI6ImRlNTRlODE3YmQ4NjM4MTI5ZWQ2ZDkxNDA1YTkwMTUyYWIzNTE4N2NkYWMxMDIxNmQ5NWI5NmUzYjgyMjAxNTFhZmU0ZDE4NWZlMzYzNTExNWMwNDFhOWY4OTNjMGZmMGFmZjFkYzBjODgyMDhmMjEwN2ZlMzk5Mzg3ZDMzZGMyZTllY2E5ODA0NDNmZjJiNjZiZDM1ZDk1YjAzY2ExMjIiLCJyZWZlcmVuY2VJZCI6IlRFU1QxMjM1ZjMzNTc3MzBlYjcxIn0.fvEsTg6OcCx2iBPMP-7e9AZtEviDqAEfTMZJib7UVQg";
$key = base64_encode("testing1234453656347nsmvfdbsrtgjnfsjhNJFDJFujragrg");
$decoded = JWT::decode($encodedString, $key, array('HS256'));
It decodes just fine on jwt.io with the secret base64 encoded option selected. What am I doing wrong here?
When the key is already Base64 encoded, you have to decode it before you pass it to JWT::decode:
$key = base64_decode("testing1234453656347nsmvfdbsrtgjnfsjhNJFDJFujragrg");
This is what JWT.io is doing when the checkbox "secret base64 encoded" is checked.
It literally means: "the secret in the input field is base64 encoded and therefore needs to be decoded".
And I can confirm that the tokens signature can be verified with this secret and "secret base64 encoded" checked.
The token is generated from a system using Java and I have to decode it in PHP.
This should generally be irrelevant. JWT is based on language independent standards.

SOAP Authentication with pre-encoded authorization string in PHP

I am working on a simple SOAP request from a server in PHP, using the standard SOAP library calls. I do not have the required username and password for authorization; however, I do have the base64-encoded authorization string (from a database) that encoding the username and password would provide. I don't seem to be able to find an example that uses the already-encoded authorization string. Is there a) a technique I can use that allows and transmits the pre-encoded string, and/or b) a function that allows me to parse out the username and password from the encoded string so I can pass those as params?
TIA for any help you can offer!
I figured out the answer:
The base-64 encoded string is simply the login and password encoded. I just decoded the string using base64_decode and split the string on the semicolon (:) symbol. Here's what the code looks like -
$loginAry = split(":", base64_decode(my_encoded_string_here));
$login = $loginAry[0];
$pwd = $loginAry[1];
and used the decoded values to log into the application. Simple as that.

SagePay Form - Success/Failure Url failing when encoded to RFC1738

We're just upgrading to form v3.0 and whilst doing so, refactoring our code.
Whilst doing so, we noticed that when using http_build_query which takes an associative array and converts it into an RFC1738 valid URL, that SagePay fails with the following error:
The SuccessURL format is invalid
The form submitting to the SagePay endpoint has an enctype of application/x-www-form-urlencoded.
However... If we manually build the string to encrypt by doing:
$tmp = '';
foreach ($crypt_store as $key => $value) {
$tmp .= sprintf('&%s=%s', $key, $value);
}
It works...
Now as I understand RFC1738, if an url exists within an url, it should be encoded, i.e.
RFC1738:
&VendorTxCode=Test&SuccessUrl=http%3A%2F%2Fwww.stackoverflow.com%3Fa%3Da%26b%3Db&FailureUrl...
SagePay:
&VendorTxCode=Test&SuccessUrl=http://www.stackoverflow.com?a=a&b=b&FailureUrl...
Surely if SagePay are following RFC1738, encoding the URL should work? Or is it because the string is encrypted which means it doesn't really matter?
Any thoughts?
Thanks
Gavin
You are correct. Because the Success / Failure URLs are encrypted within the Crypt field, there is no need to encode them.

Parsing JSON POST PHP, unable to generate object

I've done this many times before with various SAAS services, but I can't parse the supposedly JSON responses I'm getting from Blitline image processing's API.
Here's what I do to handle the POST:
$body=#file_get_contents('php://input');
print_r($body);
results=%7B%22original_meta%22%3A%7B%22width
OR
$body=rawurldecode($body);
print_r($body);
results={"original_meta":{"width ...
When I go to print $body->original_meta->width, I get an empty string. You'll realize I didn't json_decode() the $body but that's because that returns an empty string too.
Removing the results= with substr($body, 8) doesn't help either.
Can anyone help?
Expanding on my comment: the POST data is standard x-www-form-urlencoded data so there's no need to access the raw POST data. You can simply access the $_POST array that contains the URL decoded data:
$data = json_decode($_POST['results']);
echo $data->original_meta->width;
Ok this is pretty ugly but it works...
$body = file_get_contents('php://input');
$body=rawurldecode($body);
$body=substr($body, 8);
$body=json_decode($body);
echo $body->original_meta->width; //1936

Verifying a notification signature (PHP)

I need to validate a signature for a callback from ankoder.com who provide the following description:
It is the URL-escaped string of Base64-encoded HMAC-SHA1 digest of your private key and the URL-unescaped message.
$passkey = urlencode(base64_encode(hash_hmac('sha1', urldecode($str), $private_key, true)));
They provide the following Ruby example
encoded_signature = CGI.escape Base64.encode64(HMAC::SHA1::digest(private_key, CGI.unescape(message))).strip
I run this on sample data I have returned from a callback but am not getting the same signature. How do I replicate the Ruby code in PHP?
Edit
The issue was trailing whitespace being sent through.
Your PHP code matches the Ruby code. The problem must be somewhere else.
Check if the key is correct and the message is parsed correctly (urldecode, then json_decode).

Categories