最近在寫銷售系統,由於會把order id給客戶,主管反應這樣會被會看出銷售量,所以要改成亂數,避免競爭對手等看出銷售數量。
研究了半天,自己用padding、加亂數的方法似乎還是會被察覺,google後,覺得還是用加密比較簡單
Four ways to generate unique id by PHP
How to generate Unique Order Id (just to show touser) with actual Order Id?
研究了半天,自己用padding、加亂數的方法似乎還是會被察覺,google後,覺得還是用加密比較簡單
- two way encryption
先下載加密法encryption_class.php
在encryption_class.php裡,有以下兩行
此加密法是簡單的利用代換字母做加密,記得叫Caesar Cipher什麼的,主要利用自己的key,去對應scramble相同字母的位置$this->scramble1 = '! #$%&()*+,-./0123456789:;>=<?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~'; $this->scramble2 = 'f^jAE]okIOzU[2&q1{3`h5w_794p@6s8?BgP<dFV=m D>TcS%Ze|r:lGK/uCy.Jx)HiQ!#$~(;Lt-R}Ma,NvW+Ynb*0X';
當然這樣1對1的對應,很容易就被破,所以裡面的function _applyFudgeFactor(),就是在每次計算代換字母就偏移順序
利用scramble1把key轉換成順序,每次再偏移位置,從scramble2取出該字母當祕文
- 產生加密後的order id
結果如下<?php include 'encryption_class.php'; $crypt = new encryption_class(); $key = "A-COMPLETELY-RANDOM-KEY-THAT-I-HAVE-USED"; // Min length of 8 for encrypted string $min_length = 8; $order_id = 123456789; print "Original: " . $order_id . PHP_EOL; $encrypt_result = $crypt->encrypt($key, $order_id, $min_length); print "Encrypted: " . $encrypt_result . PHP_EOL; // DECRYPT $decrypt_result = $crypt->decrypt($key, $encrypt_result); print "Decrypted: " . $decrypt_result . PHP_EOL; ?>
Original: 123456789
Encrypted: 2UD5UIK9S
Decrypted: 123456789
- 以數字實作
不過問題又來了,因為order id用integer,所以要求全是數字
- 轉ascii code
就直接全轉3位數的ascii code
$numeric_cipher=''; for($i=0;$i<strlen($decrypt_result);$i++){ $numeric_cipher .= str_pad(ord(substr($decrypt_result,$i,1)),3,'0',STR_PAD_LEFT); //不到3碼,左邊補0至3碼 }
不過實在太長了,5位數就要長到15個數字
所以ascii百位數後全不用,即d(100),e(101),...
這樣padding就只要2位,這樣5位數也只要10個數字 - 還嫌太長!?最終極版大絕!!!
由於key是對應scremble的排序...
把key跟scremble都只放數字,這樣............ 應該夠短了吧...
就是有點容易猜...不過一時間內應該也夠用了
order id太長,將來要查也不好查
- 改encryption_class.php
//把scramble改成如下,不要重覆,順序可亂擺,不要一樣就好 $this->scramble1 = '0123456789'; $this->scramble2 = '2135794680';
- 改key值
因為要對應scramble,所以key有什麼值,scramble就要有什麼值,否則對應不到
至於密文min length長度,當超過明文長度時,預設是在字串後方補上空格
但因為得全為數字,所以scramble沒有空格,造成空格對應不到,因此不能超過order id的長度
//key可隨意變化,但key的值一定要出現在scramble裡 $key='1234534567890'; $key='11223344'; $key='68490'; $min_length = strlen($order_id); //因為1對1,所以不能超過order id的長度
這就可以看出來,當key、scramble、偏移量相同,位於前面的字母相同時,代碼都會相同,變化不夠大,忘了那資安的名詞叫什麼,意思是當原文變化不大時,密文的變化仍要夠大,如md5等Original Encrypted Decrypted 1 5 1 7 0 11 50 11 99 19 99 100 583 100 101 585 101 110 505 110 111 507 111
因為可變化的太少了,不過應該算堪用了
另外還有兩個問題
- original為7時,沒辦法反解
原作者在decrypt用empty,所以遇到0會當false,改!isset即可
相同的,當encrypt 0時,也會當成false,也需要改成!isset - decrypt result為0xx
雖是正常,不過ordre id用integer,這個0就會不見,到時會解不回去
由於是全數字,又密文長度不能超過明文長度,實在容易被猜出來
那如何超過明文長度咧...
解法:不補空格,補0,在明文字串前方補足0,由於integer前面有0,也是當成0,所以沒差
ex. $id = 50; $min_length = 4;
$id = '0050'; // 補2個0,足4位
在encryption_class.php裡
function encrypt(){ ... //$source = str_pad($source, $sourcelen); //原作法 $source = str_pad($source, $sourcelen, '0', STR_PAD_LEFT); //新的作法 ...
- 改encryption_class.php
- 轉ascii code
Four ways to generate unique id by PHP
How to generate Unique Order Id (just to show touser) with actual Order Id?