在构建restful架构服务或简单的查询时,往往会遇到参数明文的问题。
例如: xxxx.jsp?id=3
这种常见的URL有个潜在的苦逼之处就是,别人可以轻易做个爬虫把你的从id=1~N的数据爬走。你忙半天过几天就发现有个站和你一样……
解决方法之一是加密url,把id=3变成诸如id=qweoqwuiqlqjeu11312ljlqow之类的玩意
网上搜刮来的一个类,略微修改以便实用。
import java.io.UnsupportedEncodingException;import java.text.SimpleDateFormat;import java.util.Date;import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;public class DESede { //算法DESede private static final String Algorithm = "DESede"; //工作模式CBC(ECB),填充模式PKCS5Padding(NoPadding) //eg: DESede/CBC/PKCS5Padding, DESede/ECB/PKCS5Padding private static final String Transformation = "DESede/CBC/PKCS5Padding"; //向量iv,ECB不需要向量iv,CBC需要向量iv //CBC工作模式下,同样的密钥,同样的明文,使用不同的向量iv加密 会生成不同的密文 private static final String Iv = "\0\0\0\0\0\0\0\0"; public String encryptMode(byte[] keybyte, byte[] src) { try { // 根据给定的字节数组和算法构造一个密钥 SecretKey deskey = new SecretKeySpec(keybyte, Algorithm); // 加密 IvParameterSpec iv = new IvParameterSpec(Iv.getBytes()); Cipher c1 = Cipher.getInstance(Transformation); c1.init(Cipher.ENCRYPT_MODE, deskey, iv); return byte2hex(c1.doFinal(src)); } catch (java.security.NoSuchAlgorithmException e1) { e1.printStackTrace(); } catch (javax.crypto.NoSuchPaddingException e2) { e2.printStackTrace(); } catch (java.lang.Exception e3) { e3.printStackTrace(); } return null; } public String byte2hex(byte[] b) { // 一个字节的数, // 转成16进制字符串 String hs = ""; String stmp = ""; for (int n = 0; n < b.length; n++) { // 整数转成十六进制表示 stmp = (java.lang.Integer.toHexString(b[n] & 0XFF)); if (stmp.length() == 1) hs = hs + "0" + stmp; else hs = hs + stmp; } return hs; // 转成大写 } public String encode(String src,String key)throws UnsupportedEncodingException { //加密过的 String encryptData = encryptMode(key, src); return encryptData; } public String decode(String src,String key)throws UnsupportedEncodingException { //解密过的 String decryptData = decryptMode( getKeyByte(key), hex2byte(src.getBytes())); return decryptData; } public String encryptMode(String key, String src) throws UnsupportedEncodingException { return encryptMode(getKeyByte(key), src.getBytes()); } public byte[] getKeyByte(String key) throws UnsupportedEncodingException { // 加密数据必须是24位,不足补0;超出24位则只取前面的24数据 byte[] data = key.getBytes(); int len = data.length; byte[] newdata = new byte[24]; System.arraycopy(data, 0, newdata, 0, len > 24 ? 24 : len); return newdata; } public String decryptMode(byte[] keybyte, byte[] src) { try { // 生成密钥 SecretKey deskey = new SecretKeySpec(keybyte, Algorithm); // 解密 IvParameterSpec iv = new IvParameterSpec(Iv.getBytes()); Cipher c1 = Cipher.getInstance(Transformation); c1.init(Cipher.DECRYPT_MODE, deskey, iv); byte[] data = c1.doFinal(src); return new String(data); } catch (java.security.NoSuchAlgorithmException e1) { e1.printStackTrace(); } catch (javax.crypto.NoSuchPaddingException e2) { e2.printStackTrace(); } catch (java.lang.Exception e3) { e3.printStackTrace(); } return null; } public byte[] hex2byte(byte[] b) { if ((b.length % 2) != 0) throw new IllegalArgumentException("长度不是偶数"); byte[] b2 = new byte[b.length / 2]; for (int n = 0; n < b.length; n += 2) { String item = new String(b, n, 2); // 两位一组,表示一个字节,把这样表示的16进制字符串,还原成一个进制字节 b2[n / 2] = (byte) Integer.parseInt(item, 16); } return b2; }}
网上能找到不少代码,然而其中一部分的问题在于编码和转换是巨坑。这个很好,直接能用。
应用时,
编码就调用encode,把id=xx的xx, encode(xx,key1)得到个乱码字符串n。只有decode(n,key1)才能解开
public class xxxx{ private String key1="aaaa123231313"; private String key2="qweqeweqweqw"; ……
public void function 解码URL获取真正参数值并处理(…String n…){ //n是id=n,那串乱码 DESede ss = new DESede(); updateKey(); //可以把key1,key2等根据日期和预设字符混淆生成下新的 String number=ss.decode(n,key1); //检查number是否有效格式,如果是null就请来访者吃error,有效就照常查数据库 …… } }
很简单的,但是很实用。
我不会告诉你爬虫搞得服务器日志增长巨快有多恶心。