PHPToken (Token) design application PHP Token (Token) design objective: avoid repeated data submission. check whether an external commit matches the action to be executed. (if multiple logics are implemented on the same page, such as adding, deleting, and modifying them, put them in a php file) the token mentioned here is a hidden FORM item (type = hidden) written to FORM when the page is displayed ). the token cannot be in plain text. if it is in plain text, it is too dangerous to use a certain encryption method. the ciphertext must be reversible. the algorithm is very idiotic, so I adopted a ready-made method on the Internet.
How to achieve the goal:
How to avoid repeated submission?
You need to store an array in the SESSION, which is saved as the token successfully submitted. when processing in the background, first determine whether the token is in this array. If yes, it indicates repeated submission.
How do I check the routes?
Optional. The current session_id is added when the token is generated. if someone else copies your html (token one burst copy), the session_id contained in the token is not equal to the current session_id theoretically during submission, you can determine that this submission is an external commit.
How to match the action to be executed?
During the token operation, you need to write the token action name into the token. in this way, you can parse the action and compare it during processing.
The GToken I wrote earlier cannot reach the second one mentioned above. I modified it today and added function 2. I personally feel that it is okay.
Let's take a look at the code and tell us what is unreasonable! Thank you.
I am looking for a method on the Internet to encrypt it. I made a slight modification.
Class GEncrypt extends GSuperclass {
Protected static function keyED ($ txt, $ encrypt_key ){
$ Encrypt_key = md5 ($ encrypt_key );
$ Ctr = 0;
$ Tmp = "";
For ($ I = 0; $ I If ($ ctr = strlen ($ encrypt_key) $ ctr = 0;
$ Tmp. = substr ($ txt, $ I, 1) ^ substr ($ encrypt_key, $ ctr, 1 );
$ Ctr ++;
}
Return $ tmp;
}
Public static function encrypt ($ txt, $ key ){
// $ Encrypt_key = md5 (rand (0, 3 ));
$ Encrypt_key = md5 (float) date ("YmdHis") + rand (random gain ,99999999999999999). rand (100000,999999 ));
$ Ctr = 0;
$ Tmp = "";
For ($ I = 0; $ I If ($ ctr = strlen ($ encrypt_key) $ ctr = 0;
$ Tmp. = substr ($ encrypt_key, $ ctr, 1). (substr ($ txt, $ I, 1) ^ substr ($ encrypt_key, $ ctr, 1 ));
$ Ctr ++;
}
Return base64_encode (self: keyED ($ tmp, $ key ));
}
Public static function decrypt ($ txt, $ key ){
$ Txt = self: keyED (base64_decode ($ txt), $ key );
$ Tmp = "";
For ($ I = 0; $ I $ Md5 = substr ($ txt, $ I, 1 );
$ I ++;
$ Tmp. = (substr ($ txt, $ I, 1) ^ $ md5 );
}
Return $ tmp;
}
}
?>
GToken. inc. php
Method:
A, granteToken parameter: formName, that is, action name. key is the encryption/decryption key.
Returns a string in the format of encryption (formName: session_id)
B. isToken parameter: indicates the result generated by granteToken, formName, action name, and fromCheck. if it is true, check whether the session_id in the token is the same as the current session_id.
C. dropToken. after a successful action is executed, call this function to record the token to the session,
The code is as follows:
/**
* Principle: a unique token, base64 (time + rand + action)
* If the token is submitted, it indicates that the token is used. you can follow the token to avoid repeated submission.
*
*/
Class GToken {
/**
* Get all the current tokens.
*
* @ Return array
*/
Public static function getTokens (){
$ Tokens = $ _ SESSION [GConfig: SESSION_KEY_TOKEN];
If (empty ($ tokens )&&! Is_array ($ tokens )){
$ Tokens = array ();
}
Return $ tokens;
}
/**
* Generate a new Token
*
* @ Param string $ formName
* @ Param encryption key $ key
* @ Return string
*/
Public static function granteToken ($ formName, $ key = GConfig: ENCRYPT_KEY ){
$ Token = GEncrypt: encrypt ($ formName. ":". session_id (), $ key );
Return $ token;
}
/**
* Deleting a token actually adds an element to an array of sessions, indicating that the token has been used to avoid repeated data submission.
*
* @ Param string $ token
*/
Public static function dropToken ($ token ){
$ Tokens = self: getTokens ();
$ Tokens [] = $ token;
GSession: set (GConfig: SESSION_KEY_TOKEN, $ tokens );
}
/**
* Check whether the specified Token is used.
*
* @ Param string $ the token value to be checked
* @ Param string $ formName
* @ Param boolean $ fromCheck whether to check the route. if it is true, it determines whether the session_id appended to the token is the same as the current session_id.
* @ Param string $ key encryption key
* @ Return boolean
*/
Public static function isToken ($ token, $ formName, $ fromCheck = false, $ key = GConfig: ENCRYPT_KEY ){
$ Tokens = self: getTokens ();
If (in_array ($ token, $ tokens) // if yes, it indicates that it is a used token.
Return false;
$ Source = split (":", GEncrypt: decrypt ($ token, $ key ));
If ($ fromCheck)
Return $ source [1] = session_id () & $ source [0] = $ formName;
Else
Return $ source [0] = $ formName;
}
}
?>
Example:
First, retrieve the token from $ _ POST and use isToken to judge the token.
It seems that there is no problem.
If you want to determine whether the matching action is executed, you can change the formName in isToken to run it. it is very good and does not match. this proves successful.
Can I avoid repeated submission? I didn't verify it. it's too simple logic.
The rest is to determine whether the road check is normal.
Copy the html generated in the preceding example to a local webpage (for the purpose of different domains), run the script, and check whether the origin is unknown, no action is executed (set the third parameter of isToken to true ).
Set the third parameter of isToken to false, submit, and the specified action is executed!