【玩轉 Postman 接口測試與開發2_018】第14章:利用 Postman 初探 API 安全測試

book cover for the 2nd version

《API Testing and Development with Postman》最新第二版封面

文章目錄

  • 第十四章 API 安全測試
    • 1 OWASP API 安全清單
      • 1.1 相關背景
      • 1.2 OWASP API 安全清單
      • 1.3 認證與授權
      • 1.4 破防的對象級授權(Broken object-level authorization)
      • 1.5 破防的屬性級授權(Broken property-level authorization)
      • 1.6 不受控制的資源消耗(Unrestricted resource consumption)
      • 1.7 不受限制地訪問業務流(Unrestricted access to business workflows)
      • 1.8 不安全地使用 API 接口(Unsafe consumption of APIs)
    • 2 模糊測試(Fuzzy)
      • 2.1 相關概念
      • 2.2 實戰:在 Postman 中執行模糊測試
      • 2.3 繞開 Collection Runner 的測試方案
    • 3 利用 Postman 內置隨機變量實現模糊測試
    • 4 小結

寫在前面
本章為全書的倒數第二章,作者簡要介紹了 API 安全測試的相關概念,并對 OWASP API 安全清單和模糊測試(Fuzzy Testing)進行了重點講解;后半部分作者利用數據驅動測試演示了模糊測試在 Postman 中的具體應用,只可惜在實現方案和敘述的條理性上較為敷衍,導致我在實測過程中又踩了不少坑。特此梳理出來,既是對自己創新方案的復盤,也能讓更多后來者少走彎路。

第十四章 API 安全測試

本章概要

  • OWASP API 安全清單
  • Postman 進行模糊測試(Fuzz testing)的方法

1 OWASP API 安全清單

1.1 相關背景

  • OWASP(Open Web Application Security Project)是一個非營利組織,專注于提高軟件安全性;
  • 提供免費、開放的資源,如工具、文檔、論壇等,幫助開發者和安全人員構建安全的應用程序;
  • 知名項目包括 OWASP Top 10(十大 Web 應用安全風險)和 API Security Top 10(API安全十大風險);
  • 相關資源:
    • 網站門戶:https://owasp.org/;
    • 2023 最新版 API 安全清單:https://owasp.org/www-project-api-security/;

1.2 OWASP API 安全清單

  • API Security Top 10 是 OWASP 針對 API 安全的核心文檔,羅列了 API 面臨的十大安全風險。
  • 適用于開發者、安全工程師和架構師,幫助識別和緩解API安全威脅。

1.3 認證與授權

黑客最先嘗試的攻擊方式是身份驗證,即通過用戶名密碼攻擊。

最簡單的方式是暴力破解(brute-force attack),因此 API 接口應采取在一定時間段內 限制登錄次數 的防護措施。

具體實現:以 GitPod 演示項目為例,可利用 Postman 內置的隨機數據變量高頻多次調用登錄接口(多次手動點擊或 Collection Runner 設置迭代次數):

測試腳本:

for (let i = 0, len = 50; i < len; i++) {pm.sendRequest({url: pm.variables.replaceIn('{{base_url}}/token'),method: 'POST',header: { 'Content-Type': 'multipart/form-data'},body: {mode: "formdata",formdata: [{ key: 'username', value: pm.variables.replaceIn('{{$randomUserName}}') },{ key: 'password', value: pm.variables.replaceIn('{{$randomPassword}}') }]}},function (err, resp) {if (err) {console.error(JSON.parse(err));return;}pm.test(`${i + 1}: Response JSON have detail attribute`, function () {pm.expect(resp.json()).to.eql({ "detail": "Incorrect user name or password" });});})
}

實測結果(鑒權接口疑似不具備限制登錄次數功能):

圖 14.1 構造不同的用戶名和密碼,多次高頻調用登錄接口,模擬暴力破解過程

【圖 14.1 構造不同的用戶名和密碼,多次高頻調用登錄接口,模擬暴力破解過程】

1.4 破防的對象級授權(Broken object-level authorization)

這是 2023 年十大安全清單排名第一的高風險議題:

  • 問題描述:未正確驗證用戶對對象的訪問權限,導致越權訪問。
  • 應對措施:實施嚴格的權限驗證,確保用戶只能訪問授權資源。
  • 示例:用登錄普通用戶(user1/12345)的登錄令牌去訪問管理員帳號,看看示例項目是否會響應 403 錯誤。

實測結果:

圖 14.2 用 user1 的登錄令牌訪問管理員 admin 的帳號信息,后臺報 403 錯誤(符合預期)

【圖 14.2 用 user1 的登錄令牌訪問管理員 admin 的帳號信息,后臺報 403 錯誤(符合預期)】

1.5 破防的屬性級授權(Broken property-level authorization)

示例:用 user1/12345 登錄,先用 "user1" 為創建人(即 create_by 字段)添加一個正常的待辦項,然后看看是否可以通過 PUT 請求篡改該創建人信息(例如改為 "user2")。

測試腳本:

// PUT request's Post-response
pm.collectionVariables.set('reqPut', pm.request);// Pre-request
pm.sendRequest(pm.collectionVariables.get('reqPut'),function(err, resp) {if(err) {console.error('Updated failure:', err);return;}pm.test('PUT req: status code should be 200', () => {console.log(resp)pm.expect(resp.code).to.eq(200);});}
)// Post-response
pm.test('The creator should not be updated (user1) after running PUT req',() => {const [{ created_by: creator }] = pm.response.json();pm.expect(creator).to.eql('user1')});

實測結果:

圖 14.3 實測屬性級授權漏洞(篡改失敗,符合預期)

【圖 14.3 實測屬性級授權漏洞(篡改失敗,符合預期)】

但實測發現,在創建待辦項時人為設置創建人為 非當前登錄用戶(如 "user2"),最后仍然創建成功了,說明該接口還是有問題的:

圖 14.4 創建任務時篡改創建人信息,最終任務創建成功,說明該接口仍然支持篡改信息

【圖 14.4 創建任務時篡改創建人信息,最終任務創建成功,說明該接口仍然支持篡改信息】

1.6 不受控制的資源消耗(Unrestricted resource consumption)

方式一:通過耗盡所有系統資源來損害系統,導致系統癱瘓(denial-of-service attacks,拒絕服務攻擊);

方式二:由于未對接口調用次數進行限制,大量請求將拖慢響應速度;如果接口調用了第三方付費資源,還會產生大量費用。

1.7 不受限制地訪問業務流(Unrestricted access to business workflows)

攻擊者可能會利用抓包、監控請求數據等方式獲取系統內部通信 API,從而獲悉內部工作流結構,給系統帶來嚴重威脅(例如惡意逃票等)。

應對措施:仔細考慮暴露了哪些接口;嚴格控制接口訪問權限。

1.8 不安全地使用 API 接口(Unsafe consumption of APIs)

典型案例:引用了被黑客攻擊的第三方 API。

這類測試較為棘手,可能需要搭建一個模擬服務器,讓從第三方 API 響應的數據在該模擬器上先行緩沖,或者模擬危險數據進行測試,看看本地后臺是否能夠鑒別該類數據。

2 模糊測試(Fuzzy)

2.1 相關概念

定義:模糊測試(Fuzzy) 是一種通過向程序提供無效、隨機或意外的輸入來發現漏洞和錯誤的測試技術。

主要特征:

  • 非通用測試技術
  • 有助于發現未考慮到、或未測試到的問題

具體的運行方式:

  • 手動執行:通過在 UI 中輸入偽隨機數據來完成(極少);
  • 編程執行:以程序的形式運行(絕大多數)。工具如 PeachFuzzer 或自定義輸入集。

輸入的生成:

  • 生成大量隨機或半隨機數據,可能包含格式錯誤或危險字符(如轉義字符、引號等)。
  • 輸入通常是隨機的,但有一些邊界限制(例如,字節 vs ASCII/Unicode 字符串)。
  • 輸入可以偏向已知的“危險”字符(例如轉義字符、引號等)。

輸入內容的具體方式:

  • 通過命令行參數注入
  • 通過文件輸入
  • 通過網絡協議
  • 通過 API 輸入(特別適合模糊測試,易于用程序控制)

模糊查詢的應用場景:

  • 安全測試場景:揭示未能預見的攻擊方向,發現錯誤處理機制中的薄弱環節等;
  • API 測試場景:具有易于訪問且數量巨大的測試輸入,尤其適合 API 測試。

2.2 實戰:在 Postman 中執行模糊測試

GitHub 開源項目 Big List of Naughty StringsJSON 文件為數據源,利用 Collection RunnerGitPod 演示項目 ToDo List App 進行基于數據驅動的模糊測試,看看 POST /tasks 接口在大量隨機輸入下的響應情況。

首先從開源項目下載原始數據文件 blns.base64.json。該原始數據為 Base64 編碼的字符串數組:

["", "dW5kZWZpbmVk", "dW5kZWY=", "bnVsbA==", ...
]

使用前需要先處理成如下格式(可使用 vim 宏的批量操作完成):

[{"naughtyString":""}, {"naughtyString":"dW5kZWZpbmVk"}, {"naughtyString":"dW5kZWY="}, {"naughtyString":"bnVsbA=="}, ...
]

然后創建測試集合 FuzzyTest 以及 POST 請求 Create a task,其 URL 設置為 {{base_url}}/tasks,其中 base_url 為集合變量,其值為 GitPod 演示項目的基礎 URL(啟動鏈接:https://gitpod.io/new/#https://github.com/djwester/todo-list-testing)。

接著,在測試請求的請求體中輸入如下內容(這里有個大坑,后面會講):

{"description": "{{naughtyString}}","status": "Draft"
}

上述代碼中的 naughtyString 為數據驅動測試啟動后、經 Pre-request 腳本處理得到的動態變量:

const atob = require('atob');
const encoded_string = pm.iterationData.get("naughtyString");
pm.collectionVariables.set('naughtyString', atob(encoded_string));

對應的 Post-response 響應后腳本如下:

pm.test("Status code is 201", function() {pm.response.to.have.status(201);
});

一切準備就緒后,啟動 Collection Runner,加載 JSON 映射文件,執行模糊測試:

圖 14.5 利用 Collection Runner,發起基于JSON 文件數據驅動的模糊測試

【圖 14.5 利用 Collection Runner,發起基于JSON 文件數據驅動的模糊測試】

由于是分別讀取每行數據并調用創建接口,整個過程需要多等些時間,最終得到結果:

圖 14.6 Collection Runner 運行結束后的實測截圖

【圖 14.6 Collection Runner 運行結束后的實測截圖】

由于作者演示時用的是本地部署的 ToDo List App,全套數據測完只用了 1'14",和我實測時的 23'56" 真是天壤之別(沒辦法,Python 基礎有限,幾次嘗試本地部署都失敗了)。但奇怪的是,除了 10 個請求因為網絡原因發送失敗,其余 666 個都成功了,并沒有報錯。

可高興不到一分鐘,我就知道出問題了。作者并沒有交代要用 user2 登錄,而我新增任務前壓根兒就沒登錄,導致后續的數據清空全部失敗了:

圖 14.7 由于新增任務時沒有登錄,導致后續的批量刪除全部失敗(神坑)

【圖 14.7 由于新增任務時沒有登錄,導致后續的批量刪除全部失敗(神坑)】

沒辦法,只能重置項目,重新來過……

Ctrl + C 中斷 GitPod 項目,運行重置數據命令 poetry run python remove_tables.py,然后執行 make run-dev 重新啟動。

這次先用 user2/12345 換取登錄令牌,再到新增接口中完成鑒權:

圖 14.8 用 user2 的登錄令牌完成新增接口的鑒權設置

【圖 14.8 用 user2 的登錄令牌完成新增接口的鑒權設置】

然后只選取新增接口,再次上傳 JSON 數據集運行 Collection Runner

圖 14.9 重新運行 Collection Runner 的配置界面截圖

【圖 14.9 重新運行 Collection Runner 的配置界面截圖】

也不知道是不是這份死磕精神感動了馬克思,第二次運行居然全部成功了:

圖 14.10 第二次運行結果截圖(676 條數據全部新增成功)

【圖 14.10 第二次運行結果截圖(676 條數據全部新增成功)】

接著在瀏覽器查看項目首頁,也沒有書中說的 alert 注入問題(當真歐皇附體?):

img14.11

借著這波好運,趕緊再跑一遍數據批量清空。在 GET {{base_url}}/task 接口的響應后腳本中輸入以下內容(直接用 JS 腳本批量刪除,書中方法太過陳舊,還得再消耗一次 Collection Runner 免費額度,不知道作者怎么想的):

const tasks = pm.response.json();
const task_ids = tasks.map(t => t.id);const base_url = pm.collectionVariables.get('base_url');
const auth = {type: 'bearer',bearer: [{key: 'token',value: pm.collectionVariables.replaceIn('{{token}}'),type: 'string'}]
};
const getCallback = task_id => (err, response) => {if(err) {console.error(err);return;}pm.test(`Deleting id(${task_id}): Status should be OK`, function() {pm.expect(response.status).to.eql('OK');});
};for(const id of task_ids) {// Delete the task by idpm.sendRequest({url: `${base_url}/tasks/${id}`,method: 'DELETE',auth}, getCallback(id));
}

結果還是報錯:

img14.12

仔細一想,真相大白了:新增接口必須在請求體中手動指定 created_by 字段,否則 一律按匿名處理(就當是作者故意挖的坑吧)。

只有再重來一遍了:

img14.13

再次執行批量刪除,只有一次是后臺原因刪除失敗,五次請求未發送,其余全部刪除成功,終于熬出頭了:

img14.14

2.3 繞開 Collection Runner 的測試方案

其實只要具備 JavaScript 基礎,完全可以跳過 Collection Runner 的限制,在 Pre-request / Post-response 腳本中實現批量新增和刪除。

批量新增的純 JS 腳本實現:

  1. 將原始 JSON 數據集不經任何處理直接放到 Postman 的私有模塊中,例如 my-blns

    const data = ["", "dW5kZWZpbmVk", "dW5kZWY=", "bnVsbA==", "TlVMTA==", "KG51bGwp", // ..."e3sgIiIuX19jbGFzc19fLl9fbXJvX19bMl0uX19zdWJjbGFzc2VzX18oKVs0MF0oIi9ldGMvcGFz","c3dkIikucmVhZCgpIH19"
    ];
    module.exports = {data
    };
    
  2. 新建請求 GET {{base_url}}/tasks,用于在批量新增后查詢總的待辦項列表:

    1. Pre-request 中輸入以下腳本:
    const atob = require('atob');
    const { data } = pm.require('your/package/path/to/my-blns');
    // console.log(data.length);const postRequest = description => ({url: pm.collectionVariables.replaceIn('{{base_url}}/tasks'),method: 'POST',header: { 'Content-Type': 'application/json' },body: {mode: 'raw',raw: JSON.stringify({description,status: "Draft",created_by: "user2"})}
    });data.map(d => atob(d)).map((description, i) => pm.sendRequest(postRequest(description), (err, resp) => {if(err) {console.error(err);return;}pm.test(`Create task_${i+1} completed: the status code should be 201`,() => pm.expect(resp.code).to.eql(201));}));
    
    1. Post-response 輸入以下腳本:

      pm.test('Task list length should be greater than 0', function () {pm.expect(pm.response.json()).to.be.an('array').and.to.have.lengthOf.at.least(1, "Task list length should be greater than 0");
      });
      
  3. 至于批量刪除,剛才實測過程中已經看過腳本了,這里只說明一下實現邏輯。利用列表查詢接口 GET {{base_url}}/tasks 獲取到任務列表后,批量提取任務列表的 id;然后分別調用 DELETE 接口 POST {{base_url}}/tasks/:id 完成刪除(注意:刪除待辦項時,別忘了在請求中帶上鑒權配置對象 auth)。

這樣就可以在 Postman 中隨意批量新增和刪除待辦任務了,完全不受 Collection Runner 的制約。

3 利用 Postman 內置隨機變量實現模糊測試

其實就是將上傳的 JSON 文件內容用 Postman 內置的各種隨機變量實現同樣的模糊測試效果,例如將新增接口請求體中的 JSON 改為:

{"description": "{{$randomLoremSentence}}","status": "Draft","created_by": "user2"
}

或者借助測試腳本,引入 lodash 實現更多模糊測試效果:

const _ = require('lodash');
// _.sample(collection): Gets a random element from collection.
const description = _.sample(["{{$randomAbbreviation}}", "{{$randomAdjective}}"]);
const jsonBody = {description,"status", "Draft","created_by": "user2"
}

4 小結

本章內容整體感覺較敷衍,上半部分介紹相關概念幾乎全是蜻蜓點水式的描述,后半段實戰環節的條理性又明顯不如前面的章節,漏掉很多關鍵細節,且在方案選擇上過分依賴 Collection Runner,致使我在實測過程中浪費了不少免費額度。不過依次填完這些坑后,我也有機會用純 JavaScript 腳本的方式實現待辦任務的批量創建與刪除,順便學習了用 pm.sendRequest() 發送 POST 請求和 DELETE 請求的寫法,也算是因禍得福了吧。

后記
最后再跟大家分享個操作技巧,遇到不會寫的 Postman 腳本,可以利用其自帶的 AI 機器人 Postbot 直接給答案。本章實測中幾種 pm.sendRequest() 的寫法就是這么來的,比查官方文檔快多了。大家一定要學會使用 AI 工具,千萬不要故步自封,成為 AI 時代的 “新文盲”。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/68165.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/68165.shtml
英文地址,請注明出處:http://en.pswp.cn/web/68165.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring @PropertySource:讓你的應用配置更加模塊化和可維護

PropertySource注解在Spring中的作用&#xff0c;就像是給Spring應用配了一個“外部配置箱”。 想象一下&#xff0c;你在開發一個Spring應用時&#xff0c;有很多配置信息需要設置&#xff0c;比如數據庫的連接信息、應用的某些功能開關等。如果這些信息都硬編碼在代碼中&…

RK3576——USB3.2 OTG無法識別到USB設備

問題&#xff1a;使用硬盤接入到OTG接口無熱插拔信息&#xff0c;接入DP顯示屏無法正常識別到顯示設備&#xff0c;但是能通過RKDdevTool工具燒錄系統。 問題分析&#xff1a;由于熱插拔功能實現是靠HUSB311芯片完成的&#xff0c;因此需要先確保HUSB311芯片驅動正常工作。 1. …

docker-compose 配置nginx

前言 前端打包的dist文件在宿主機&#xff0c;nginx運行在docker-compose 問題 nginx.conf 在本地配置可以生效&#xff0c;但是鏈接到容器就報錯 基于本地的nginx運行&#xff0c;本地nginx.conf 如下 server {listen 8081;location / {root /usr/local/software/testweb/…

基于SpringBoot+ Vue的家教管理系統

隨著互聯網技術的發展&#xff0c;信息化管理已經深入到各個行業中。在教育領域&#xff0c;家教管理系統的需求日益增長。傳統的手工管理方式在面對大量信息時&#xff0c;容易出現管理效率低下、數據錯誤率高、修改困難等問題。本文將介紹基于Spring Boot框架、MySQL數據庫開…

【數據結構】樹哈希

目錄 一、樹的同構1. 定義2. 具體理解(1) 結點對應(2) 孩子相同(3) 遞歸性質 3. 示例 二、樹哈希1.定義2.哈希過程&#xff08;1&#xff09;葉節點哈希&#xff08;2&#xff09;非葉節點哈希&#xff08;3&#xff09;組合哈希值 3.性質&#xff08;1&#xff09; 唯一性 \re…

使用DeepSeek的技巧筆記

來源&#xff1a;新年逼自己一把&#xff0c;學會使用DeepSeek R1_嗶哩嗶哩_bilibili 前言 對于DeepSeek而言&#xff0c;我們不再需要那么多的提示詞技巧&#xff0c;但還是要有兩個注意點&#xff1a;你需要理解大語言模型的工作原理與局限,這能幫助你更好的知道AI可完成任務…

【工具篇】ChatGPT:開啟人工智能新紀元

一、ChatGPT 是什么 最近,ChatGPT 可是火得一塌糊涂,不管是在科技圈、媒體界,還是咱們普通人的日常聊天里,都能聽到它的大名。好多人都在討論,這 ChatGPT 到底是個啥 “神器”,能讓大家這么著迷?今天咱就好好嘮嘮。 ChatGPT,全稱是 Chat Generative Pre-trained Trans…

【centOS】搭建公司內網git環境-GitLab 社區版(GitLab CE)

1. 安裝必要的依賴 以 CentOS 7 系統為例&#xff0c;安裝必要的依賴包&#xff1a; sudo yum install -y curl policycoreutils openssh-server openssh-clients postfix sudo systemctl start postfix sudo systemctl enable postfix2. 添加 GitLab 倉庫 curl -sS https:/…

$route 和 $router 的區別是什么?

在 Vue Router 中,$route 和 $router 是兩個不同的對象,它們各自承擔著不同的角色。下面是它們的主要區別: 一、$route 定義$route 是當前路由的信息對象,包含了與當前路由相關的狀態和參數。它是一個只讀對象。 2. 主要屬性 params:動態路由參數,例如 /user/:id 中的 …

node.js 08 express的使用和熱重載nodemon的安裝

一.express的安裝和使用 安裝 npm i express 使用 //引入express const express require(express)//啟動服務器 const app express()//設置get請求地址&#xff0c;獲取請求地址信息&#xff0c;和發送返回的數據 app.get(/bailan,(req, res) > {//req.query可以獲取到客…

Python因為網絡原因安裝依賴庫報錯

現象 在終端運行以下指令 pip install pyautogui pillow keyboard 出現報錯&#xff0c;終端信息如下&#xff1a; PS D:\code\Python> pip install pyautogui pillow keyboard Collecting pyautoguiUsing cached PyAutoGUI-0.9.54.tar.gz (61 kB)Installing build depe…

面試問題記錄1

問題一&#xff1a;性能測試步驟 性能測試步驟主要包括以下幾個階段&#xff1a; ?1. 需求分析階段? 明確測試目標&#xff0c;了解性能測試需求&#xff0c;包括業務列表、性能指標、測試環境、數據量等詳細需求?12。熟悉項目相關的資源&#xff0c;如架構設計、軟硬件環…

開源 GPU 集群管理器 GPUStack 輕松拉起deepseek各版本模型

GPUStack 是一個用于運行 AI 模型的開源 GPU 集群管理器。 項目地址&#xff1a;gpustack/gpustack: Manage GPU clusters for running AI modelshttps://github.com/gpustack/gpustackhttps://github.com/gpustack/gpustackhttps://github.com/gpustack/gpustackhttps://githu…

ESP32開發學習記錄---》GPIO

she 2025年2月5日&#xff0c;新年后決定開始充電提升自己&#xff0c;故作此記,以前沒有使用過IDF開發ESP32因此新年學習一下ESP32。 ESPIDF開發環境配置網上已經有很多的資料了&#xff0c;我就不再贅述&#xff0c;我這里只是對我的學習經歷的一些記錄。 首先學習一個…

3-kafka服務端之控制器

文章目錄 概述控制器的選舉與故障恢復控制器的選舉故障恢復 優雅關閉分區leader的選舉 概述 在Kafka集群中會有一個或多個broker&#xff0c;其中有一個broker會被選舉為控制器&#xff08;Kafka Controler&#xff09;&#xff0c;它負責管理整個集群中所有分區和副本的狀態。…

物聯網的三層架構:感知層、網絡層與應用層

物聯網&#xff08;Internet of Things, IoT&#xff09;作為現代科技的重要組成部分&#xff0c;正在深刻改變我們的生活和工作方式。它將物理世界與數字世界無縫連接&#xff0c;通過智能設備、傳感器和網絡技術&#xff0c;實現數據的采集、傳輸和應用。物聯網的架構通常分為…

react的antd表單校驗,禁止輸入空格并觸發校驗提示

首先需要用到form組件&#xff0c;在form.item內添加rules屬性&#xff0c;寫正則表達式 <Form.Itemlabel"員工姓名"name"name"rules{[{ required: true, message: 員工姓名 },{ pattern: /^(?!\s*$).$/, message: 不能全是空格 },]}> <Input p…

JavaScript addEventListener事件列表

addEventListener 方法用于向指定元素添加事件監聽器&#xff0c;當該對象觸發指定的事件時&#xff0c;指定的回調函數就會被執行。以下是一些常見的事件類型 鼠標事件 click: 當用戶點擊某個對象時觸發。 dblclick: 當用戶雙擊某個對象時觸發。 contextmenu&#xff1a;當…

IDEA 中集成 Maven,配置環境、創建以及導入項目

目錄 在 IntelliJ IDEA 中集成 Maven 并配置環境 1. 打開 IDEA 設置 2. 定位 Maven 配置選項 3. 配置 Maven 路徑 4. 應用配置 創建 Maven 項目 1. 新建項目 2. 選擇項目類型 3. 配置項目信息 4. 確認 Maven 設置 5. 完成項目創建 導入 Maven 項目 1. 打開導入窗口…

神經網絡常見激活函數 1-sigmoid函數

sigmoid 1 函數求導 sigmoid函數 σ ( x ) 1 1 e ( ? x ) \sigma(x) \frac{1}{1e^{(-x)}} σ(x)1e(?x)1? sigmoid函數求導 d d x σ ( x ) d d x ( 1 1 e ? x ) e ? x ( 1 e ? x ) 2 ( 1 e ? x ) ? 1 ( 1 e ? x ) 2 1 1 e ? x ? 1 ( 1 e ? x ) 2 …