This article deals with the MRZScanner Pro app feature, that allows a user to send scanned data to a server.
App settings:
* HTTPS Method - user can choose between the HTTP methods: POST and GET.
* HTTPS Address - the server URL. The address must be SSL secured (https).
* Encryption key - unique security key used for generating the security_hash (explained below). The key must be a hex number, 20 digits long.
Request JSON:
* results - array of the documents to be sent.
* security_data - unique security data parameter used for generating the security_hash.
* security_hash - md5 encryption of security_data + encryption_key.
Example code in KOTLIN of what the app will do:
val security_data = System.currentTimeMillis().toString()
//lets get a UNIX timestamp in miliseconds, we will use this as a control security data parameter and compare the times on the app and the server
val security_hash = md5Hash(security_data + sharedPreferencesHelper.getEncryptionKeySetting()) //concatenate our 20 digits long encryption key (which is typed into the app) with the security data and md5 hash it
...
FormUrlEncoded
@POST(“{fullUrl}“)
fun postToServer(@Path(value = “fullUrl”, encoded = true) fullUrl: String,
@Field(“results”) results: String,
@Field(“security_data”) security_data: String,
@Field(“security_hash”) security_hash: String): Observable<Response<ResultModel>>
//send both the security_data and the security_hash to the server side
Request example:
results=[
{
“issuing_country” : “USA”,
“dob_raw” : “850217",
“nationality” : “USA”,
“sex” : “M”,
“dob_readable” : “17 February 85",
“expiration_date_readable” : “25 June 25",
“given_names_readable” : “John”,
“expiration_date_raw” : “250625",
“optionals” : “1102982460000",
“document_type_readable” : “ID”,
“document_type_raw” : “ID”,
“surname” : “SMITH”,
“document_number” : “A1234567"
},
]
&security_data=1234567890.220734
&security_hash=7e7c462288cac0ea398d27f3f431c10e
A PHP server would handle the request described previously ( and sent from the app ) like this:
if(empty($_POST['security_data']) || empty($_POST['security_hash']) || md5($_POST['security_data'] . $privatekey) != $_POST['security_hash']){
echo json_encode(array('status'=>false,'status_type'=>'authentication error','message'=>'Authentication problem occurred'));
}
elseif(time() - $_POST['security_data'] > 120){
//120 can be increased in case the server and the app are not time synced, or this step can entirely be skipped and requests will never timeout
echo json_encode(array('status'=>false,'status_type'=>'authentication expired','message'=>'Authentication expired'));
}
else{
//The request is valid and we can do stuff with the data that is sent from the app
//here you can do your normal mySQL update or whatever database you use
$processed_data = array(); //for demo purposes the processed_data array will be empty
echo json_encode(array('status'=>true,'message'=>'Your data is save on this server!','sent_data'=>$_POST,'processed_data'=>$processed_data));
}
Expected response JSON:
* status - indicating whether the sending was successful.
* message - a descriptive message of the success/error.
* sent_data - an array of documents in the form in which the server received them.
* processed_data - an array of documents which the server successfully processed.
Response example (this can be implemented by the user in an entirely different way, the reponse bellow is just an example of how the app expects the response to be defined, in the PHP example we use this structure):
{
“status”:true,
“message”:“Data Saved”,
“sent_data”:[
{
“issuing_country”:“MKD”,
“dob_raw”:“850217",
“nationality”:“MKD”,
“sex”:“M”,
“dob_readable”:“17 February 85",
“expiration_date_readable”:“25 June 25",
“given_names_readable”:“John”,
“expiration_date_raw”:“250625",
“optionals”:“1234567890123",
“document_type_readable”:“ID”,
“document_type_raw”:“ID”,
“surname”:“SMITH”,
“document_number”:“A1234567"
}
],
“processed_data”:[
{
“issuing_country”:“MKD”,
“dob_raw”:“850217”,
“nationality”:“USA”,
“sex”:“M”,
“dob_readable”:“17 February 85”,
“expiration_date_readable”:“25 June 25”,
“given_names_readable”:“John”,
“expiration_date_raw”:“250625”,
“optionals”:“1234567890123”,
“document_type_readable”:“ID”,
“document_type_raw”:“ID”,
“surname”:“SMITH”,
“document_number”:“A1234567”
}
]
The app will do something like this:
String security_data = String.valueOf(System.currentTimeMillis());
//lets get a UNIX timestamp in miliseconds, we will use this as a control security data parameter and compare the times on the app and the server
String security_hash = md5Hash(security_data + sharedPreferencesHelper.getEncryptionKeySetting()); //concatenate our 20 digits long encryption key (which is typed into the app) with the security data and md5 hash it
...
@FormUrlEncoded
@POST("{fullUrl}")
Observable postToServer(@Path(value = “fullUrl”, encoded = true) String fullUrl,
@Field(“results”) results: String,
@Field(“security_data”) String security_data,
@Field(“security_hash”) String security_hash);
//send both the security_data and the security_hash to the server side
The security_data value is a timestamp that later we will use to check how much time has passed between the payload being generated and when the server received it;
The security_hash is just a md5 hash of the timestamp (security_data) and the encryption key that only you know (this key is entered in the app via the settings window)
Let's presume that the payload was sent via POST:
//we check if the security_data and security_hash params are present in the payload and if they are we use the encryption key //named $privatekey here together with the security_data from the post to create our control string that needs to match with the // security_hash. If they don't match then the authentication failed and you should reject the sent data
if(empty($_POST['security_data']) || empty($_POST['security_hash']) || md5($_POST['security_data'] . $privatekey) != $_POST['security_hash']){
echo json_encode(array('status'=>false,'status_type'=>'authentication error','message'=>'Authentication problem occurred'));
}
//if they do match let's check if it's recent so we only allow for requests sent in the last 2 minutes
elseif(time() - $_POST['security_data'] > 120){
//120 can be increased in case the server and the app are not time synced, or this step can entirely be skipped and requests will never timeout
echo json_encode(array('status'=>false,'status_type'=>'authentication expired','message'=>'Authentication expired'));
}
else{
//The request is valid and we can do stuff with the data that is sent from the app
//here you can do your normal mySQL update or whatever database you use
$processed_data = array(); //for demo purposes the processed_data array will be empty
echo json_encode(array('status'=>true,'message'=>'Your data was saved!','sent_data'=>$_POST,'processed_data'=>$processed_data));
}