(1)合规方案
    对于如登录、修改密码、交易等重要操作,对于用户会话下用户的设备信息是否变化做判断,当前会话下用户设备信息发生变化时,系统应终止操作,给用户返回登录界面。
    基于设备指纹的会话绑定技术,可实现应用系统对敏感业务操作的用户行为实时判别能力。
    (2)安全编码示例:
    1)获取设备指纹
    A.Android设备指纹
    对于Android客户端应用,可通过设备中获取的device ID、Pseudo-Unique ID、mac地址、cpu number、系统版本等信息进行计算(hash处理)得到唯一标识字符串,或者在客户端随机生成一个UUID字符串,然后与用户会话绑定。

    1. public static String getDeviceId(Context context) {
    2. StringBuilder deviceId = new StringBuilder();
    3. // 渠道标志
    4. deviceId.append("a");
    5. try {
    6. //wifi mac地址
    7. WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    8. WifiInfo info = wifi.getConnectionInfo();
    9. String wifiMac = info.getMacAddress();
    10. if (!isEmpty(wifiMac)) {
    11. deviceId.append("wifi");
    12. deviceId.append(wifiMac);
    13. PALog.e("getDeviceId : ", deviceId.toString());
    14. return deviceId.toString();
    15. }
    16. //IMEI(imei)
    17. TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    18. String imei = tm.getDeviceId();
    19. if (!isEmpty(imei)) {
    20. deviceId.append("imei");
    21. deviceId.append(imei);
    22. PALog.e("getDeviceId : ", deviceId.toString());
    23. return deviceId.toString();
    24. }
    25. //序列号(sn)
    26. String sn = tm.getSimSerialNumber();
    27. if (!isEmpty(sn)) {
    28. deviceId.append("sn");
    29. deviceId.append(sn);
    30. PALog.e("getDeviceId : ", deviceId.toString());
    31. return deviceId.toString();
    32. }
    33. //如果上面都没有, 则生成一个id:随机码
    34. String uuid = getUUID(context);
    35. if (!isEmpty(uuid)) {
    36. deviceId.append("id");
    37. deviceId.append(uuid);
    38. PALog.e("getDeviceId : ", deviceId.toString());
    39. return deviceId.toString();
    40. }
    41. } catch (Exception e) {
    42. e.printStackTrace();
    43. deviceId.append("id").append(getUUID(context));
    44. }
    45. PALog.e("getDeviceId : ", deviceId.toString());
    46. return deviceId.toString();
    47. }
    48. /**
    49. * 得到全局唯一UUID
    50. */
    51. public static String getUUID(Context context) {
    52. SharedPreferences mShare = getSysShare(context, "sysCacheMap");
    53. if (mShare != null) {
    54. uuid = mShare.getString("uuid", "");
    55. }
    56. if (isEmpty(uuid)) {
    57. uuid = UUID.randomUUID().toString();
    58. saveSysMap(context, "sysCacheMap", "uuid", uuid);
    59. }
    60. PALog.e(tag, "getUUID : " + uuid);
    61. return uuid;
    62. }

    B.iOS设备指纹
    对于iOS客户端应用,可通过获取IDFA、IDFV、UDID、系统版本号等设备标识,然后经过计算(hash处理)后得到唯一标识字符串,然后与服务器端用户会话进行绑定。

    1. NSString *uuid = [[NSUUID UUID] UUIDString];//获取UUID
    2. NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];//获取IDFV标识
    3. NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];//获取IDFA标识

    C.Web指纹识别
    对于web应用,结合浏览器的User Agent、语言、颜色深度、屏幕分辨率、时区、是否具有会话存储、是否具有本地存储、是否具有索引DB、IE是否指定AddBehavior、是否有打开的DB、CPU类型、平台、是否DoNotTrack、已安装的Flash字体列表、Canvas指纹、WebGL指纹、浏览器的插件信息、是否安装AdBlock等,然后这些值通过散列函数传递产生指纹来对用户的设备进行精确识别后,与会话进行绑定。

    1. var fingerprint = new Fingerprint().get();

    2)会话与设备指纹绑定
    用户登录时,服务器端应对同一客户端登录的用户数量和一个用户同时在多个客户端登陆进行限制,将设备信息与用户会话绑定,并且对会话进行监听。实现方案如下:
    建立用户登录会话操作类,在用户登录时将用户名、设备信息、Session id存到Session中去。

    1. public class UserSessionAdd {
    2. private String clientInfo;
    3. private String sessID;
    4. private String userName;
    5. public String getUserName() {
    6. return userName;
    7. }
    8. public void setUserName(String username) {
    9. this.userName = username;
    10. }
    11. public String getClient() {
    12. return clientInfo;
    13. }
    14. public void setClient(String client) {
    15. this.clientInfo = client;
    16. }
    17. public String getSessid() {
    18. return sessID;
    19. }
    20. public void setSessID(String sessid) {
    21. this.sessID = sessid;
    22. }
    23. }

    建立一个监听器,实现HttpSessionAttributeListener接口,监听每一个Attribute的增加、编辑、删除事件。监听器中还要建立一个map,将所有的session放入这个map中。

    1. public class MyListener implements HttpSessionAttributeListener {
    2. Map<String, HttpSession> map = new HashMap<String, HttpSession>();
    3. //对用户Session操作进行监听
    4. public void attributeAdded(HttpSessionBindingEvent event) {
    5. String name = event.getName();
    6. if (name.equals("usa")) {
    7. UserSessionAdd usa = (UserSessionAdd) event.getValue();
    8. if (map.get(usa.getAdd()) != null) {
    9. HttpSession sess = map.get(usa.getAdd());
    10. //获取用户Session Attribute
    11. UserSessionAdd usa1 = (UserSessionAdd) sess.getAttribute("usa");
    12. sess.removeAttribute("usa");
    13. sess.invalidate();
    14. }
    15. map.put(usa.getAdd(), event.getSession());
    16. }
    17. }
    18. public void attributeRemoved(HttpSessionBindingEvent event) {
    19. String name = event.getName();
    20. if (name.equals("usa")) {
    21. UserSessionAdd usa = (UserSessionAdd) event.getValue();
    22. map.remove(usa.getAdd());
    23. }
    24. }
    25. public void attributeReplaced(HttpSessionBindingEvent event) {
    26. // TODO Auto-generated method stub
    27. `
    1. }
    2. }
    1. web.xml中配置监听器,对会话进行监听。
    2. ```xml
    3. <listener>
    4. <listener-class>监听器类的路径,如:com.web.MyListener</listener-class>
    5. </listener>

    用户登录时,将获取到的设备信息、Session ID、用户名存入Session,实现的监听器会对用户的会话进行监听并依据安全要求进行操作。

    1. //获取用户设备指纹信息
    2. String userClient = getClientInfo(request.getRemoteHost());
    3. String sessionId = request.getSession().getId();
    4. UserSessionAdd usa = new UserSessionAdd();
    5. usa.setUserName(username);
    6. usa.setSessID(sessionId);
    7. usa.setClient(userClient);
    8. request.getSession().setAttribute(“usa”, usa);