整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          接口的安全設計要素:ticket,簽名,時間戳

          不點藍字,我們哪來故事?

          概述

          與前端對接的API接口,如果被第三方抓包并進行惡意篡改參數,可能會導致數據泄露,甚至會被篡改數據,我主要圍繞時間戳,token,簽名三個部分來保證API接口的安全性

          請求服務器超時怎么辦_請求中時間戳與服務器_請求時間參數異常是什么意思

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

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

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

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

          開放接口

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

          請求中時間戳與服務器_請求時間參數異常是什么意思_請求服務器超時怎么辦

          /*
          ?*?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?openDemo(int?personId){
          ????????return?tokenSignService.getPersonList(personId);
          ????}
          }

          Token認證獲取

          用戶登錄成功后,會獲取一個ticket值,接下去任何接口的訪問都需要這個參數。我們把它放置在redis內,有效期為10分鐘,在ticket即將超時,無感知續命。延長使用時間,如果用戶在一段時間內沒進行任何操作,就需要重新登錄系統。擴展:

          @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簽名

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

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

          ????public?static?Boolean?checkSign(HttpServletRequest?request,String?sign){
          ????????Boolean?flag=?false;
          ????????//檢查sigin是否過期
          ????????Enumeration?pNames?=??request.getParameterNames();
          ????????Map?params?=?new?HashMap();
          ????????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("現在的sign-->>"?+?sign);
          ????????System.out.println("驗證的sign-->>"?+?getSign(params,secretKeyOfWxh));
          ????????if(sign.equals(getSign(params,?secretKeyOfWxh))){
          ????????????flag?=?true;
          ????????}
          ????????return?flag;
          ????}

          重復訪問

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

          請求中時間戳與服務器_請求服務器超時怎么辦_請求時間參數異常是什么意思

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

          ????????long?timestampsStr?=?timestampLong?/?1000;

          ????????return?timestampsStr;
          ????}

          需要跟當前服務器時間進行對比,如果超過一分鐘,就拒絕本次請求,節省服務器查詢數據的消耗

          攔截器

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

          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是否即將過期,進行續命操作
          ????????????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());
          ????????????//判斷是否重復訪問,存在重放攻擊的時間窗口期
          ????????????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;
          ????}
          }

          訪問

          先登錄系統,獲取合法的ticket

          請求中時間戳與服務器_請求時間參數異常是什么意思_請求服務器超時怎么辦

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

          請求中時間戳與服務器_請求時間參數異常是什么意思_請求服務器超時怎么辦

          demo代碼

          往期推薦

          多點控制單元 選擇轉發單元 tutorial 1 documentation

          選擇性轉發單元 SFU( Unit)在各個端點之間交換音頻和視頻流。 每個接收器方可以選擇它所要接收的流和層(空間/時間上)。 與 MCU(多點控制單元)相比,這種設計可以帶來更好的性能、更高的吞吐量和更少的延遲。 鑒于它不做轉碼或合成媒體,所以它具有高度可擴展性,并且需要的資源少得多。

          由于各個端點分別獲取其他端點的媒體,因此它們可以具有個性化的布局,并選擇自己所要呈現的媒體流,以及決定如何顯示它們。

          SFU 可以看作一個多媒體流的路由器,實踐中可以應用發布訂閱模式( publish/ pattern)

          libuv

          refer to

          room-<unique room ID>: {
                  description = This is my awesome room
                  is_private = true|false (private rooms don't appear when you do a 'list' request, default=false)
                  secret = <optional password needed for manipulating (e.g. destroying) the room>
                  pin = <optional password needed for joining the room>
                  require_pvtid = true|false (whether subscriptions are required to provide a valid private_id
                                          to associate with a publisher, default=false)
                  publishers = <max number of concurrent senders> (e.g., 6 for a video
                                          conference or 1 for a webinar, default=3)
                  bitrate = <max video bitrate for senders> (e.g., 128000)
                  bitrate_cap = <true|false, whether the above cap should act as a limit to dynamic bitrate changes by publishers, default=false>,
                  fir_freq = <send a FIR to publishers every fir_freq seconds> (0=disable)
          

          單元轉發控制點選擇方法_城區控制所屬單元_多點控制單元 選擇轉發單元

          audiocodec = opus|g722|pcmu|pcma|isac32|isac16 (audio codec to force on publishers, default=opus can be a comma separated list in order of preference, e.g., opus,pcmu) videocodec = vp8|vp9|h264|av1|h265 (video codec to force on publishers, default=vp8 can be a comma separated list in order of preference, e.g., vp9,vp8,h264) vp9_profile = VP9-specific profile to prefer (e.g., "2" for "profile-id=2") h264_profile = H.264-specific profile to prefer (e.g., "42e01f" for "profile-level-id=42e01f") opus_fec = true|false (whether inband FEC must be negotiated; only works for Opus, default=false) video_svc = true|false (whether SVC support must be enabled; only works for VP9, default=false) audiolevel_ext = true|false (whether the ssrc-audio-level RTP extension must be negotiated/used or not for new publishers, default=true) audiolevel_event = true|false (whether to emit event to other users or not, default=false) audio_active_packets = 100 (number of packets with audio level, default=100, 2 seconds) audio_level_average = 25 (average value of audio level, 127=muted, 0='too loud', default=25) videoorient_ext = true|false (whether the video-orientation RTP extension must be negotiated/used or not for new publishers, default=true) playoutdelay_ext = true|false (whether the playout-delay RTP extension must be negotiated/used or not for new publishers, default=true) transport_wide_cc_ext = true|false (whether the transport wide CC RTP extension must be

          城區控制所屬單元_多點控制單元 選擇轉發單元_單元轉發控制點選擇方法

          negotiated/used or not for new publishers, default=true) record = true|false (whether this room should be recorded, default=false) rec_dir = <folder where recordings should be stored, when enabled> lock_record = true|false (whether recording can only be started/stopped if the secret is provided, or using the global enable_recording request, default=false) notify_joining = true|false (optional, whether to notify all participants when a new participant joins the room. The Videoroom plugin by design only notifies new feeds (publishers), and enabling this may result extra notification traffic. This flag is particularly useful when enabled with require_pvtid for admin to manage listening only participants. default=false) require_e2ee = true|false (whether all participants are required to publish and subscribe using end-to-end media encryption, e.g., via Insertable Streams; default=false) }

          ? 2021 ~ 2023, Walter Fan, Commons -- 4.0 License.

          Built with Sphinx using by Read the Docs.


          主站蜘蛛池模板: 国产a∨精品一区二区三区不卡| 一区二区三区精品高清视频免费在线播放 | 国产精品自在拍一区二区不卡| 国产高清视频一区三区| 熟女精品视频一区二区三区| 中文字幕一区二区三区精华液| 色狠狠色噜噜Av天堂一区| 久久亚洲AV午夜福利精品一区| 国产对白精品刺激一区二区| 国模极品一区二区三区| 国产福利电影一区二区三区,亚洲国模精品一区| 狠狠综合久久av一区二区| 久久久人妻精品无码一区| 人妻无码第一区二区三区| 国产午夜精品一区二区三区极品| 国产一区二区三区亚洲综合| 国产一区二区内射最近更新| 中文乱码人妻系列一区二区| 一区二区不卡久久精品| 日韩精品无码一区二区中文字幕| 鲁丝丝国产一区二区| 日韩精品成人一区二区三区| 亚洲av无一区二区三区| 国产在线精品一区二区不卡麻豆| 无码乱人伦一区二区亚洲一| 国产乱码精品一区三上| 亚洲一区二区三区首页| 北岛玲在线一区二区| 亚洲国产情侣一区二区三区| 免费视频精品一区二区| 亚洲一区二区三区久久久久| 亚洲国产精品一区二区第一页免| 亚洲国产一区在线观看| 国产精品无码一区二区在线观一 | 成人国产一区二区三区| 国产精品99精品一区二区三区| 国模丽丽啪啪一区二区| 国产精品综合一区二区三区| 99久久人妻精品免费一区| 一区二区三区无码高清视频| 一区二区传媒有限公司|