首頁>技術>

目錄

為什麼選擇微服務?

1.透過設計確保安全

OWASP

2.掃描依賴

3.隨處使用HTTPS

安全的GraphQL API

安全的RSocket端點

4.使用身份令牌

授權伺服器:多對一還是一對一?

在JWT上使用PASETO令牌

5.加密和保護金鑰

6.透過交付流水線驗證安全性

7.降低攻擊者的速度

8.使用Docker Rootless模式

9.使用基於時間的安全性

10.掃描Docker和Kubernetes配置中的漏洞

11.瞭解雲和叢集安全性

總結

為什麼選擇微服務?

如果你正在開發一個大型/複雜的應用,並且你經常需要快速,可靠地升級部署 ,那麼微服架構是一個不錯的選擇。

但是如何提高微服務架構的安全性呢?

1.透過設計確保安全

設計安全,意味著從一開始就應該將安全性納入軟體設計中。關於安全,其中最常見的一個威脅就是惡意字元。

什麼是惡意字元,實際上取決於它所使用的上下文。只是要找出是否存在其他注入

攻擊(即JavaScript,SQL等),你就可以確保HTML上下文中沒有惡意字元。需要注意的是,HTML文件的編碼也是基於上下文的。

限制字元也不總是可行的。在許多情況下,軟體認為是惡意的字元,但這在某人的名字中是完全有效的字元。那應該怎麼辦?

我覺得,最好在使用字元的上下文中判斷,而不是嘗試限制字元。

—羅伯·溫奇

作為工程師,我們很早就明白了–建立精心設計的軟體體系結構的重要性。軟體開發中常見的安全威脅,促使組織在系統架構時要時刻考慮軟體的安全性。系統要能夠在受到攻擊時,也要有用於執行必要的身份驗證,授權,資料加密,資料完整性和可用性的解決方案。

從InfoQ文章分析中,我們可以看到:OWASP Top 10在過去十年中並沒有發生太大變化。SQL注入仍然是最常見的攻擊。十年來,我們仍在繼續重複同樣的錯誤。— Johnny Xmas

這就是為什麼需要將安全預防措施納入軟體架構的原因。

OWASP

開源的Web應用程式安全專案(Open Web Application Security Project ,OWASP)是一個非營利性基金會,致力於改善軟體的安全性。他們向開發人員和技術人員提供:

工具和資源社群與網路教育培訓

我喜歡Dan Bergh Johnsson,Daniel Deogun和Daniel Sawano撰寫的《Secure by Design》一書中的示例。它們展示瞭如何開發一個基本User實體物件,並且該物件需要在web頁面上顯示使用者名稱。

public class User {   private final Long id;   private final String username;   public User(final Long id, final String username) {      this.id = id;      this.username = username;   }   // ...}

如果你接受使用者名稱的任何字串值,則有人可以使用使用者名稱執行XSS攻擊。你可以使用輸入校驗來解決此問題,如下所示。

import static com.example.xss.ValidationUtils.validateForXSS;import static org.apache.commons.lang3.Validate.notNull;public class User {   private final Long id;   private final String username;   public User(final Long id, final String username) {      notNull(id);      notNull(username);      this.id = notNull(id);      this.username = validateForXSS(username);   }}

但是,此程式碼仍然有問題。

開發人員需要考慮安全漏洞開發人員必須是安全專家並且知道使用 validateForXSS()它假設編寫程式碼的人可以想到現在或將來可能發生的每一個潛在弱點

更好的設計是建立一個Username封裝所有安全問題的類。

import static org.apache.commons.lang3.Validate.*;public class Username {   private static final int MINIMUM_LENGTH = 4;   private static final int MAXIMUM_LENGTH = 40;   private static final String VALID_CHARACTERS = "[A-Za-z0-9_-]+";   private final String value;       public Username(final String value) {      notBlank(value);      final String trimmed = value.trim();      inclusiveBetween(MINIMUM_LENGTH,                       MAXIMUM_LENGTH,                       trimmed.length());      matchesPattern(trimmed,                     VALID_CHARACTERS,                     "Allowed characters are: %s", VALID_CHARACTERS);      this.value = trimmed;   }   public String value() {      return value;   }}public class User {   private final Long id;   private final Username username;   public User(final Long id, final Username username) {      this.id = notNull(id);      this.username = notNull(username);}

這樣,你的設計使開發人員更容易編寫安全程式碼。

2.掃描依賴

我們用於開發軟體的許多類庫,很多都依賴於第三方類庫,傳遞性依賴性有時會產生大量的依賴鏈,其中一些可能就有安全漏洞。

你可以在程式碼儲存庫上,使用掃描程式來識別易受攻擊的依賴項。你也應該在部署的流水線,主要程式碼行,釋出的程式碼版本和新的程式碼貢獻中掃描漏洞。

Snyk調查:25%的專案未報告安全問題;多數只添加發行說明;只有10%的人報告CVE。

如果你是GitHub使用者,則可以使用dependabot透過pull請求提供自動更新。GitHub還可以在儲存庫中啟用安全警報。

你還可以使用功能更全的解決方案,例如Snyk和JFrog Xray。

3.隨處使用HTTPS

你應該在所有地方都使用HTTPS,即使對於靜態站點也要如此。如果你有HTTP連線,請將其更改為HTTPS,確保工作流程的各個方面(從Maven儲存庫到 XSDs )都使用HTTPS URI。

HTTPS的正式名稱是:傳輸層安全性(又名TLS)。它旨在確保計算機應用程式之間的隱私和資料完整性。 How HTTPS Works 是一個很好的網站,可用於學習有關HTTPS的更多資訊。

要使用HTTPS,你需要一個證書。它具有兩個重要的作用, 建立資訊保安通道,保障隱私資料安全 ,並且還驗證網站的真實性,防止誤入釣魚網站 。

Let’s Encrypt 提供免費證書,你可以使用其API自動續訂它們。

Let’s Encrypt於2016年4月12日啟動,該組織宣佈自成立以來已總共發行了10億張

證書,並且據估計,Let’s Encrypt使Internet上安全網站的百分比增加了一倍。

Let’s Encrypt建議你使用Certbot來獲取和更新證書。Certbot是一個免費的開源軟體工具,其中Certbot網站可以讓你選擇你的Web伺服器和系統,然後自動生成證書。例如,Ubuntu使用Nginx的的說明。

要在Spring Boot中使用證書,你只需要在src/main/resources/application.yml進行一些配置。

server:  ssl:    key-store: classpath:keystore.p12    key-store-password: password    key-store-type: pkcs12    key-alias: tomcat    key-password: password  port: 8443

在配置檔案中儲存密碼和金鑰,有很大的安全風險。我將在下面顯示如何加密金鑰。

你可能還想強制使用HTTPS。你可以在我以前的部落格文章“ 保護Spring Boot應用程式的10種出色方法”中看到如何做。通常,強制使用HTTPS,需要使用HTTP Strict-Transport-Security響應頭(縮寫為HSTS)來告訴瀏覽器它們只能使用HTTPS訪問網站。

要了解基於Spring的微服務如何使用HTTPS,請參閱使用HTTPS和OAuth 2.0保護Spring微服務。

安全的GraphQL API

GraphQL 既是一種用於 API 的查詢語言也是一個滿足你資料查詢的執行時。 GraphQL 對你的 API 中的資料提供了一套易於理解的完整描述,使得客戶端能夠準確地獲得它需要的資料,而且沒有任何冗餘,也讓 API 更容易地隨著時間推移而演進,還能用於構建強大的開發者工具。

如果你想請求具備OAuth 2.0和React功能的GraphQL伺服器,則只需傳遞一個Authorization標頭即可。

Apollo是一個用於構建資料圖表的平臺,Apollo Client具有React和Angular的功能。

const clientParam = { uri: '/graphql' };const myAuth = this.props && this.props.auth;if (myAuth) {  clientParam.request = async (operation) => {    const token = await myAuth.getAccessToken();    operation.setContext({ headers: { authorization: token ? `Bearer ${token}` : '' } });  }}const client = new ApolloClient(clientParam);

Angular配置安全的Apollo Client

export function createApollo(httpLink: HttpLink, oktaAuth: OktaAuthService) {  const http = httpLink.create({ uri });  const auth = setContext((_, { headers }) => {    return oktaAuth.getAccessToken().then(token => {      return token ? { headers: { Authorization: `Bearer ${token}` } } : {};    });  });  return {    link: auth.concat(http),    cache: new InMemoryCache()  };}

在伺服器上,你可以使用任何用於保護REST API端點的安全來保護GraphQL。

安全的RSocket端點

RSocket是用於構建雲原生和微服務應用程式的下一代的響應式的第5層應用程式通訊協議。

這是什麼意思?這意味著RSocket具有內建的響應式語義,因此它可以與客戶端可靠地通訊。RSocket網站介紹,它可應用於 Java,JavaScript,Go, .NET, C++, 和Kotlin中。

Spring Security 5.3.0完全支援RSocket應用程式。

要了解有關RSocket的更多資訊,我建議閱讀RSocket入門:Spring Boot Server。

4.使用身份令牌

OAuth 2.0自2012年以來就提供了委託授權。2014年,OpenIDConnect在的OAuth 2.0之上添加了聯合身份。它們共同提供了一個標準規範,你可以據此編寫程式碼,並可以在 IdPs (Identity Providers) 中使用。

該規範,還允許你透過向/userinfo端點發送訪問令牌來查詢使用者的身份。你可以使用OIDC發現來查詢此端點的URI,這提供了一種獲取使用者身份的標準方法。

如果要在微服務之間進行通訊,則可以使用OAuth 2.0的客戶端憑據流來實現安全的伺服器到伺服器通訊。在下圖中,API Client是一臺伺服器,而API Server另一臺伺服器。

授權伺服器:多對一還是一對一?

如果你使用OAuth 2.0保護服務安全,使用的還是授權伺服器。典型的設定是多對一關係,在這種關係中,你有許多微服務與授權伺服器通訊。

這種方法的優點:

服務可以使用訪問令牌與任何其他內部服務進行對話(因為它們都是連線到同一個授權伺服器)有了一個可以查詢所有範圍和許可權定義的地方開發人員和安全人員更易於管理互動更快

缺點:

如果一項服務的令牌遭到破壞,則所有服務都將面臨風險安全邊界模糊

另一種更安全的替代方法是一對一方法,其中每個微服務都繫結到其自己的授權伺服器。如果他們需要相互通訊,則需要在信任之前進行註冊。

這種體系結構使你可以明確定義安全邊界。但是,它比較慢,也難於管理。

我的建議:使用多對一關係,直到你有計劃和文件來支援一對一關係為止。

在JWT上使用PASETO令牌

在過去的幾年中, JSON Web Tokens (JWT) 變得非常流行,但也遭到了抨擊。主要是因為許多開發人員嘗試使用JWT,來避免會話的伺服器端儲存。請參閱為什麼不建議使用JWT。

我的同事Randall Degges和Brian Demers在PASETO( platform-agnostic security tokens)上寫了一些有益的文章。

全面瞭解PASETO用Java建立和驗證PASETO令牌

長話短說:使用PASETO令牌並不像聽起來那麼容易。如果你想編寫自己的安全性,則可以使用它。但是,如果你要使用知名的雲提供商,則很可能它還不支援PASETO標準。

5.加密和保護金鑰

當你開發與授權伺服器或其他服務通訊的微服務時,這些微服務可能會儲存用於通訊的金鑰。這些金鑰可能是API金鑰,客戶金鑰或用於基本身份驗證的憑據。

要更安全地使用金鑰,第一步是將其儲存在環境變數中。但這只是開始,你應該盡力加密你的金鑰。

在Java世界中,我最熟悉HashiCorp Vault和Spring Vault。

下圖展示的是Amazon KMS是如何工作。

簡而言之,它的工作方式是:

使用KMS生成主金鑰每次你想要加密資料時,你都要求AWS 為你生成一個新的資料金鑰。然後,你可以使用資料金鑰對資料進行加密然後,Amazon將使用主金鑰對你的資料金鑰進行加密然後,你將合併加密的資料金鑰和加密的資料以建立加密的訊息。該加密的訊息是你的最終輸出,你就可以將它儲存在檔案或資料庫中。

這樣,你就無需擔心保護金鑰的安全性-金鑰始終是唯一且安全的。你還可以使用Azure KeyVault來儲存你的金鑰。

6.透過交付流水線驗證安全性

依賴關係和容器掃描,從源頭保障了程式的安全,但是在執行CI(持續整合)和CD(持續部署)流水線時,還應該執行測試。

Atlassian有篇文章,DevSecOps:將安全性注入CD流水線,建議使用安全性單元測試,靜態分析安全性測試(SAST)和動態分析安全性測試(DAST)。

你的程式碼交付流水線可以自動執行這些安全檢查,但是可能會花費一些時間來設定。

可以瞭解一種“ Continuous Hacking ”的軟體交付方法,請參閱Zach Arnold和Austin Adams的這篇文章。他們建議以下內容:

建立Docker基本映象的白名單,以在構建時進行檢查確保你正在拉取的基礎映象有加密簽名對推送的映象的元資料進行簽名,以便稍後進行檢查在你的容器中,請使用軟體包完整的Linux發行版使用HTTPS拉取第三方依賴不允許在Dockerfile中,將敏感的主機路徑指定為映象中的儲存卷

但是程式碼呢?

針對已知的程式碼級安全漏洞在程式碼庫上執行靜態程式碼分析執行自動的依賴檢查程式,以確保你使用的是最新,最安全的依賴版本啟動服務,將自動滲透機器人指向正在執行的容器,然後看看會發生什麼

有關程式碼掃描器,請參見OWASP的原始碼分析工具。

7.降低攻擊者的速度

如果有人嘗試使用數百個使用者名稱/密碼組合,攻擊你的API,那麼他們可能需要一段時間才能成功完成身份驗證。如果你可以檢測到此攻擊並降低服務速度,則攻擊者很可能會消失。

你可以在程式碼中或API閘道器來實現速率限制。Okta提供了API速率限制和電子郵件速率限制以幫助降低服務攻擊。

8.使用Docker Rootless模式

Docker 19.03引入了Rootless模式,此功能,允許使用者以主機上的非root使用者身份執行Docker守護程序(包括容器)。這樣做的好處是,即使受到威脅,攻擊者也將無法獲得對主機的根訪問許可權。

如果你正在生產中執行Docker守護程式,那麼這絕對是你應該研究的東西。但是,如果你讓Kubernetes執行Docker容器,你需要在PodSecurityPolicy中配置runAsUser。

9.使用基於時間的安全性

基於時間的安全性背後的思想是,你的系統永遠不會完全安全。防止入侵者只是保護系統安全的一部分,異常檢測和反應也是必不可少的。

使用多因素身份驗證可以減慢入侵者的速度,還可以幫助檢測特權級別較高的人何時透過關鍵伺服器進行身份驗證。如果你擁有諸如域控制器之類的元件,來控制網路流量,那麼使用者只要登入成功,就會向你的網路管理員團隊傳送警報。

這只是嘗試檢測異常,並對異常做出快速反應的一個示例。

優先選擇基本映象使用USER指令,確保使用了最少特權簽名和驗證映象,以減少MITM攻擊查詢,修復開源漏洞不要將敏感資訊洩漏到Docker映象使用固定標籤實現不變性使用COPY代替ADD使用元資料標籤,例如maintainer和securitytxt使用多階段構建來獲取小而安全的映象使用像hadolint這樣的 linter 檢查工具11.瞭解雲和叢集安全性

如果你正在管理叢集和雲,那麼你可能已經知道4C的Cloud Native Security了。

僅在程式碼級別解決安全問題,幾乎不可能防範雲,容器和程式碼中的安全漏洞。但是,當你正確地處理這些問題時,就會為程式碼增加安全性,並將增強本已強大的基礎設施。

Kubernetes部落格上有篇文章,標題為《防止攻擊的11種方法》。

隨處使用TLS啟用具有最低許可權的RBAC,禁用ABAC並使用稽核日誌記錄使用第三方身份驗證程式(例如Google,GitHub或Okta)分散式部署你的etcd群集,併為其提供防火牆旋轉加密金鑰(Rotate Encryption Keys)使用Linux安全功能和受限制的 PodSecurityPolicy靜態分析YAML以非root使用者身份執行容器使用網路策略(以限制Pod之間的流量)掃描映象並執行IDS(入侵檢測系統)執行服務網格

這篇文章雖然釋出在2018年7月,但我認為,仍然適用於今天的雲原生世界。

總結

這些安全模式,前面幾點適用於開發人員。

透過設計確保安全掃描依存關係使用HTTPS使用訪問令牌加密和保護金鑰

它們的其餘部分似乎適用於DevOps人員,或更確切地說適用於DevSecOps。

使用交付流水線驗證安全性降低攻擊者的速度使用Docker Rootless模式使用基於時間的安全性掃描Docker和Kubernetes配置中的漏洞瞭解雲和叢集的安全性

所有這些模式都是重要的考慮因素,因此,組織應該確保開發人員和DevSecOps團隊之間保持密切的關係。實際上,如果你選擇了微服務架構,那麼這些人就不會在單獨的團隊中!

16
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 漫談程式碼智慧重構服務的設計與開發