<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          API接口的安全設(shè)計驗證:ticket,簽名,時間戳

          共 13790字,需瀏覽 28分鐘

           ·

          2021-03-16 11:10


          點擊上方 藍字 關(guān)注我們!



          Java,Python,C/C++,Linux,PHP,Go,C#,QT,大數(shù)據(jù),算法,軟件教程,前端,簡歷,畢業(yè)設(shè)計等分類,資源在不斷更新中... 點擊領(lǐng)取!

          每天 11 點更新文章,餓了點外賣,點擊 ??《無門檻外賣優(yōu)惠券,每天免費領(lǐng)!》

          作者:一劍天門

          cnblogs.com/dslx/p/14116294.html

          概述

          與前端對接的API接口,如果被第三方抓包并進行惡意篡改參數(shù),可能會導(dǎo)致數(shù)據(jù)泄露,甚至?xí)淮鄹臄?shù)據(jù),我主要圍繞時間戳,token,簽名三個部分來保證API接口的安全性

          1.用戶成功登陸站點后,服務(wù)器會返回一個token,用戶的任何操作都必須帶了這個參數(shù),可以將這個參數(shù)直接放到header里。

          2.客戶端用需要發(fā)送的參數(shù)和token生成一個簽名sign,作為參數(shù)一起發(fā)送給服務(wù)端,服務(wù)端在用同樣的方法生成sign進行檢查是否被篡改。

          3.但這依然存在問題,可能會被進行惡意無限制訪問,這時我們需要引入一個時間戳參數(shù),如果超時即是無效的。

          4.服務(wù)端需要對token,簽名,時間戳進行驗證,只有token有效,時間戳未超時,簽名有效才能被放行。

          開放接口

          沒有進行任何限制,簡單粗暴的訪問方式,這樣的接口方式一般在開放的應(yīng)用平臺,查天氣,查快遞,只要你輸入正確對應(yīng)的參數(shù)調(diào)用,即可獲取到自己需要的信息,我們可以任意修改參數(shù)值。

          /*
           * Description: 開放的接口
           * @author huangweicheng
           * @date 2020/12/21
          */

          @RestController
          @RequestMapping("/token")
          public class TokenSignController {

              @Autowired
              private TokenSignService tokenSignService;

              @RequestMapping(value = "openDemo",method = RequestMethod.GET)
              public List<PersonEntity> openDemo(int personId){
                  return tokenSignService.getPersonList(personId);
              }
          }

          Token認證獲取

          用戶登錄成功后,會獲取一個ticket值,接下去任何接口的訪問都需要這個參數(shù)。我們把它放置在redis內(nèi),有效期為10分鐘,在ticket即將超時,無感知續(xù)命。延長使用時間,如果用戶在一段時間內(nèi)沒進行任何操作,就需要重新登錄系統(tǒng)。擴展:記一次token安全認證的實踐

          @RequestMapping(value = "login",method = RequestMethod.POST)
              public JSONObject login(@NotNull String username, @NotNull String password){
                  return tokenSignService.login(username,password);
              }

          登錄操作,查看是否有這個用戶,用戶名和密碼匹配即可成功登錄。

          /** 
               * 
               * Description:驗證登錄,ticket成功后放置緩存中,
               * @param
               * @author huangweicheng
               * @date 2020/12/31   
              */
           
              public JSONObject login(String username,String password){
                  JSONObject result = new JSONObject();
                  PersonEntity personEntity = personDao.findByLoginName(username);
                  if (personEntity == null || (personEntity != null && !personEntity.getPassword().equals(password))){
                      result.put("success",false);
                      result.put("ticket","");
                      result.put("code","999");
                      result.put("message","用戶名和密碼不匹配");
                      return result;
                  }
                  if (personEntity.getLoginName().equals(username) && personEntity.getPassword().equals(password)){
                      String ticket = UUID.randomUUID().toString();
                      ticket = ticket.replace("-","");
                      redisTemplate.opsForValue().set(ticket,personEntity.getLoginName(),10L, TimeUnit.MINUTES);
                      result.put("success",true);
                      result.put("ticket",ticket);
                      result.put("code",200);
                      result.put("message","登錄成功");
                      return result;
                  }
                  result.put("success",false);
                  result.put("ticket","");
                  result.put("code","1000");
                  result.put("message","未知異常,請重試");
                  return result;
              }

          Sign簽名

          把所有的參數(shù)拼接一起,在加入系統(tǒng)秘鑰,進行MD5計算生成一個sign簽名,防止參數(shù)被人惡意篡改,后臺按同樣的方法生成秘鑰,進行簽名對比。

          /**
               * @param request
               * @return
               */

              public static Boolean checkSign(HttpServletRequest request,String sign){
                  Boolean flag= false;
                  //檢查sigin是否過期
                  Enumeration<?> pNames =  request.getParameterNames();
                  Map<String, String> params = new HashMap<String, String>();
                  while (pNames.hasMoreElements()) {
                      String pName = (String) pNames.nextElement();
                      if("sign".equals(pName)) continue;
                      String pValue = (String)request.getParameter(pName);
                      params.put(pName, pValue);
                  }
                  System.out.println("現(xiàn)在的sign-->>" + sign);
                  System.out.println("驗證的sign-->>" + getSign(params,secretKeyOfWxh));
                  if(sign.equals(getSign(params, secretKeyOfWxh))){
                      flag = true;
                  }
                  return flag;
              }

          重復(fù)訪問

          引入一個時間戳參數(shù),保證接口僅在一分鐘內(nèi)有效,需要和客戶端時間保持一致。

          public static long getTimestamp(){
                  long timestampLong = System.currentTimeMillis();

                  long timestampsStr = timestampLong / 1000;

                  return timestampsStr;
              }

          需要跟當(dāng)前服務(wù)器時間進行對比,如果超過一分鐘,就拒絕本次請求,節(jié)省服務(wù)器查詢數(shù)據(jù)的消耗

          攔截器

          每次請求都帶有這三個參數(shù),我們都需要進行驗證,只有在三個參數(shù)都滿足我們的要求,才允許數(shù)據(jù)返回或被操作。

          public class LoginInterceptor implements HandlerInterceptor {

              @Autowired
              private RedisTemplate redisTemplate;

              @Override
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws IOException {
                  JSONObject jsonObject = new JSONObject();
                  String ticket = request.getParameter("ticket");
                  String sign = request.getParameter("sign");
                  String ts = request.getParameter("ts");
                  if (StringUtils.isEmpty(ticket) || StringUtils.isEmpty(sign) || StringUtils.isEmpty(ts)){
                      jsonObject.put("success",false);
                      jsonObject.put("message","args is isEmpty");
                      jsonObject.put("code","1001");
                      PrintWriter printWriter = response.getWriter();
                      printWriter.write(jsonObject.toJSONString());
                      return false;
                  }
                  //如果redis存在ticket就認為是合法的請求
                  if (redisTemplate.hasKey(ticket)){
                      System.out.println(redisTemplate.opsForValue().getOperations().getExpire(ticket));
                      String values = (String) redisTemplate.opsForValue().get(ticket);
                      //判斷ticket是否即將過期,進行續(xù)命操作
                      if (redisTemplate.opsForValue().getOperations().getExpire(ticket) != -2 && redisTemplate.opsForValue().getOperations().getExpire(ticket) < 20){
                          redisTemplate.opsForValue().set(ticket,values,10L, TimeUnit.MINUTES);
                      }
                      System.out.println(SignUtils.getTimestamp());
                      //判斷是否重復(fù)訪問,存在重放攻擊的時間窗口期
                      if (SignUtils.getTimestamp() - Long.valueOf(ts) > 600){
                          jsonObject.put("success",false);
                          jsonObject.put("message","Overtime to connect to server");
                          jsonObject.put("code","1002");
                          PrintWriter printWriter = response.getWriter();
                          printWriter.write(jsonObject.toJSONString());
                          return false;
                      }
                      //驗證簽名
                      if (!SignUtils.checkSign(request,sign)){
                          jsonObject.put("success",false);
                          jsonObject.put("message","sign is invalid");
                          jsonObject.put("code","1003");
                          PrintWriter printWriter = response.getWriter();
                          printWriter.write(jsonObject.toJSONString());
                          return false;
                      }
                      return true;
                  }else {
                      jsonObject.put("success",false);
                      jsonObject.put("message","ticket is invalid,Relogin.");
                      jsonObject.put("code","1004");
                      PrintWriter printWriter = response.getWriter();
                      printWriter.write(jsonObject.toJSONString());
                  }
                  return false;
              }
          }

          訪問

          先登錄系統(tǒng),獲取合法的ticket

          生成一個合法的sign驗證,獲取測試ts,訪問openDemo,即可正常訪問。還可以將參數(shù)加密,將http換成https,就不一 一展開了。

          demo代碼

          https://github.com/hwc4110/spring-demo1221

          END

          往期推薦

          ElasticSearch 面試 4 連炮,你頂?shù)米∶矗?/p>

          天降紅包!

          最新!全球?qū)W術(shù)排名出爐:21所中國大學(xué)位居世界100強

          SQL 語句中 where 條件后 寫上 1=1 是什么意思!

          看完文章,餓了點外賣,點擊 ??《無門檻外賣優(yōu)惠券,每天免費領(lǐng)!》

          END



          若覺得文章對你有幫助,隨手轉(zhuǎn)發(fā)分享,也是我們繼續(xù)更新的動力。


          長按二維碼,掃掃關(guān)注哦

          ?「C語言中文網(wǎng)」官方公眾號,關(guān)注手機閱讀教程 ?


          必備編程學(xué)習(xí)資料


          目前收集的資料包括: Java,Python,C/C++,Linux,PHP,go,C#,QT,git/svn,人工智能,大數(shù)據(jù),單片機,算法,小程序,易語言,安卓,ios,PPT,軟件教程,前端,軟件測試,簡歷,畢業(yè)設(shè)計,公開課 等分類,資源在不斷更新中...


          點擊“閱讀原文”,立即免費領(lǐng)取最新資料!
          ??????
          瀏覽 66
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  四房色播开心五月天 | 大香蕉伊人综合在线 | 99色免费视频 | 久久久亚洲AV成人电影 | 无码伦理一级一区久久 |