国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【web安全】API的安全策略

RobinQu / 1006人閱讀

摘要:最近正在負責一個新平臺的構建和開發,有一個場景需要對應用做新增,修改和撤回的操作起先是因為之前寫過類型的功能,不想在和以前一樣一個操作類型一個,覺得代碼太過冗余了。

最近正在負責一個新平臺的構建和開發,有一個場景需要對應用做新增,修改和撤回的操作
起先是因為之前寫過類型的功能,不想在和以前一樣一個操作類型一個api,覺得代碼太過冗余了。
于是有了以下的構思

第一版
將當前界面所有api請求,合并成一個request,以type作為操作類型的區分,data為提交的數據

這樣當前界面所有操作都使用一個接口來處理,并且問題統一處理

處理token失效

處理catch

處理通信成功后都通知

處理權限

優化版
當設計成第一版后,我覺得操作類型暴露在外面有些不妥,起先想的是后端生成隨機碼和對應的加密值,通過解密拿到方法名。
后來優化了一下,加入了url來源的判斷,還能防止postman的攻擊
后端代碼如下:

redisImp為redis
utils為工具類
token和權限的檢查放在了外層,進入方法的都當成token和權限通過的

const apiPrefix = "ApiType:";
// 通過viewConfig生成對應配置
async function generateConfig (owner, viewConfig) {
    var viewName = viewConfig.name; // 界面名稱
    var viewMethods = viewConfig.methods; // 界面所支持的操作方法

    let key = apiPrefix + owner + ":" + viewName;
    await redisImp.del(key);
    let para = [], config = [], secret = [];
    // 生成10個長度為12的隨機碼
    for (var i = 0; i < 10; i++) {
      var randomKey = utils.generateRandomStr(12);
      config.push(randomKey);
    }
    // 生成三個10一下的數字
    var random1 = Math.ceil(Math.random() * 10);
    var random2 = Math.ceil(Math.random() * 10);
    var random3 = Math.ceil(Math.random() * 10);
    // todo 檢查3個隨機數是否相等
    var randomList = [random1, random2, random3];
    // 生成隨機碼和操作方法的關聯數據
    viewMethods.forEach(function (value, index) {
      para.push(config[randomList[index]]);
      para.push(value);
      secret.push(randomList[index]);
    })
    // aes加密
    var enc = utils.cryptedAES(secret.toString());
    let redisResult = await redisImp.hSet(key, para);
    if (redisResult.code === 200) {
      return {
        apis: config,
        secret: enc
      }
    }
    return null;
  }
  // 獲取界面的配置
  function getViewConfig (ctx) {
    var referer = ctx.request.header.referer; // 原始url
    var origin = ctx.request.header.origin; // 來源
    var config;
    if (!referer || !origin) {
        // todo 處理異常訪問
        return config;
    } else {
        var fontUrl = referer.replace(origin, "").split("?"); // 去除domain和url參數后的路徑
        switch (fontUrl[0]) {
          case "/app/base": {
            config = {
              name: "appBase", // 界面名稱
              methods: ["add", "modify", "retract"] // 界面操作權限
            }
            break;
          }
          default: {
          // todo 處理異常攻擊
          }
        }
    }
    return config;
  }
  
  // 獲取配置,暴露給前端的api接口
  const getConfig = async (ctx) => {
    const fName = _name + "getConfig";
    lifecycleLog.info("[Enter] " + fName);
    // 獲取當前用戶id
    const redisResult = await redis.GetTokenValue(ctx, "id");
    let owner;
    if (redisResult.code === 200) {
        owner = redisResult.data;
    } else {
        ctx.body = redisResult;
        return;
    }
    // 獲取界面配置
    var viewConfig = getViewConfig(ctx);
    if (viewConfig) {
      var result = await generateConfig(owner, viewConfig);
      if (result) {
        // 生成成功后返回給前端
        ctx.body = Object.assign({code: 200}, result);
      } else {
        ctx.body = controller.dataError();
      }
    } else {
      ctx.body = controller.dataError();
    }
    lifecycleLog.info("[Return] " + fName);
  }

  const appBase = require("./appBase")
  // 處理應用界面的接口
  const handleAppBaseData = async (ctx) => {
    const fName = _name + "handleAppBaseData";
    lifecycleLog.info("[Enter] " + fName);

    var viewConfig = getViewConfig(ctx);
    if (viewConfig) {
      const name = ctx.request.body.name; // 前端傳過來的操作碼
      const para = ctx.request.body.data; // 前端傳過來的數據
      let data;
      try {
        data = JSON.stringify(para);
      } catch (err) {
        ctx.body = controller.dataError();
        return;
      }
      // 驗證數據完整性
      if (controller.dataMissed(ctx, fName, ctx.request.body, name + data)) {
        return;
      }

      const redisResult = await redis.GetTokenValue(ctx, "id");
      let owner;
      if (redisResult.code === 200) {
         owner = redisResult.data;
       } else {
         ctx.body = redisResult;
         return;
       }
      // 從redis拿到當前用戶在當前界面的操做類型
      let apiType = await redisImp.hGet(apiPrefix + owner + ":" + viewConfig.name, name);
      if (apiType.code === 200) {
        if (apiType.data.length) {
          var methods = apiType.data[0];
          // 添加操作
          if (methods === "add") {
            await appBase.add(ctx, para, owner);
          } else {
            let option = {
              _id: para._id,
              owner: owner
            };
            // 檢測該用戶是否擁有該app
            const gameResult = await commonModel.getInfo(ctx, collection, option);
            if (gameResult) {
              if (gameResult.code === 200) {
                var gameDoc = gameResult.info["_doc"];
              } else {
                ctx.body = controller.dataError();
                return;
              }
            } else {
              ctx.body = controller.serverError();
              return;
            }
            // 修改操作
            if (methods === "modify") {
              await appBase.modify(ctx, para, gameDoc);
            } else if (methods === "retract") { // 撤回炒作
              await appBase.retract(ctx, gameDoc);
            } else {
              ctx.body = controller.dataError();
              return;
            }
          }
          // 如果入庫成功,則將新一輪的操作碼反給前端
          if (ctx.body.code === 200) {
            var result = await generateConfig(owner, viewConfig);
            ctx.body = Object.assign(ctx.body, result);
          }
        } else {
          ctx.body = controller.dataError();
        }
      } else {
        ctx.body = controller.serverError();
      }
    } else {
      ctx.body = controller.dataError();
    }
    lifecycleLog.info("[Return] " + fName);
  }

這是返回的結構

    前端就不上代碼了,稍微說下應該都能明白
    1. 進入界面的時候,請求getConfig
    2. 前端拿到數據進行解密
    3. 操作界面的時候,發送操作碼和數據
    4. 請求完成,拿到新的操作碼進行本地更新,并對之前的操作作出反應(數據更新/界面跳轉/彈框提示等)

延伸版
獲取界面配置,可以放在一個任何界面都會訪問的地方,統一處理,后端配好路由的url即可

解決/預防了哪些問題
1.代碼冗余問題
2.爬蟲問題(由于所有的操作入參都是動態返回且隨機生成,爬蟲們沒法按著一個接口和數據爬取數據,增大了難度)
3.非正常的訪問

以上就是我對API安全策略的想法,如有異議或新的方式歡迎評論留言。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/102750.html

相關文章

  • 論微服務安全

    摘要:微服務能夠為應用程序設計提供一種更具針對性范圍性與模塊性的實現方案。安全微服務部署模式可謂多種多樣但其中使用最為廣泛的當數每主機服務模式。在微服務環境下,安全性往往成為最大的挑戰。不同微服務之間可通過多種方式建立受信關系。 每個人都在討論微服務,每個人也都希望能夠實現微服務架構,而微服務安全也日漸成為大家關注的重要問題。今天小數與大家分享的文章,就從應用層面深入探討了應對微服務安全挑戰...

    plokmju88 評論0 收藏0
  • 如何構建安全企業混合云

    摘要:幾年前,行業預測分析人員表示,一旦企業決定了他們的云計算戰略,他們將會首先構建私有云,并在以后根據需要添加公共云服務。如果要在本地實施容器或作為云計算部署的一部分實施容器,則需要確保其工作負載是安全的。幾年前,行業預測分析人員表示,一旦企業決定了他們的云計算IT戰略,他們將會首先構建私有云,并在以后根據需要添加公共云服務。但這種事情并沒有發生。事實證明,采用云計算可以盡快讓組織的董事會分配資...

    MarvinZhang 評論0 收藏0
  • Web 應用安全性: 使用這些 HTTP 頭保護 Web 應用

    摘要:綜上所述,認為沒有提供的保護,用戶會過得更好安全研究人員并不完全反對這一決定。內容安全策略是一個額外的安全層,用于檢測并削弱某些特定類型的攻擊,包括跨站腳本和數據注入攻擊等。 這是關于web安全性系列文章的第 三 篇,其它的可點擊以下查看: Web 應用安全性: 瀏覽器是如何工作的 Web 應用安全性: HTTP簡介 目前,瀏覽器已經實現了大量與安全相關的頭文件,使攻擊者更難利用漏...

    spademan 評論0 收藏0
  • 別讓安全問題拖慢了 DevOps!

    摘要:文件完整性監測持續監控您的云服務器,保護重要的系統二進制文件和配置文件不會受到未經授權的或惡意的變更。首先會記錄下云服務器系統的清潔狀態,作為基準。您可以通過一個在線管理控制臺,監控所有的云服務器。 DEVSECOPS 所面臨的挑戰 敏捷開發和 DevOps 方法的出現使軟件開發的速度與質量都有所提升,但它們不經意地也為安全機構增壓不少。從前的安全策略是基于靜態數據的,而在產品上線前才...

    forsigner 評論0 收藏0

發表評論

0條評論

RobinQu

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<