---
# System prepended metadata

title: Celery_Security
tags: [celery 5.2, python, celery]

---

# Celery_Security
###### tags: `celery` `celery 5.2` `python`

[官方連結_Security](https://docs.celeryq.dev/en/master/userguide/security.html)
## Security
### Introduction
雖然Celery在開創之初已經考慮到安全性，但它仍然應該被視為不安全的組件。

取決於你的[安全策略](https://en.wikipedia.org/wiki/Security_policy)，你可以採取各種不同步驟來讓你的Celery安裝更加安全。
### Areas of Concern
#### Broker
保護Broker免受不需要的訪問是必要的，特別是如果公開可以訪問的Broker。預設情況下，Workers信任它們從Broker取得的資料是沒被篡改的。關於如何讓Broker連線更可靠的資訊可參考[Message Signing](https://docs.celeryq.dev/en/master/userguide/security.html#id2)。

第一線的防禦應該是在Broker前放一個防火牆，僅允許白名單機器訪問它。

請記住，防火牆配置錯誤以及暫時禁用防火牆在現實世界中是很常見的。可靠的安全性策略包含監控防火牆設備，以檢測它們是否已被禁用，無論是意外還是故意。

換句話說，也不應該盲目的信任防火牆(所以到底要我怎麼樣？)。

如果你的Broker支援細粒度訪問控制(fine-grained access control)，像是RabbitMQ，那麼你應該考慮啟用它。參考範例http://www.rabbitmq.com/access-control.html

如果你的Broker backend支援，你可以使用[broker_use_ssl](https://docs.celeryq.dev/en/master/userguide/configuration.html#std-setting-broker_use_ssl)來啟用end-to-end SSL加密與認證。
#### Client
在Celery中，"client"指向Broker發送訊息的任何東西，像是應用任務的網頁服務。

如果可以從client發送任意訊息，那適當地保護Broker也不是那麼重要了。

(這邊官方預計再補更多說明)
#### Worker
在Worker內執行任務的預設權限與Worker本身權限是相同的。這觀念可以套用到資源，像是記憶體、文件系統與設備。

這個規則的例外是，當使用基於multiprocessing的task pool(目前預設就是task pool)。這種情況下，任務將會因為`fork()`的調用而獲得所有的記憶體複本，並將有權限訪問由父任務(parenet tasks)於相同Worker child process中的寫入的記憶體內容。


可以透過啟動子程序(subprocess)(fork() + execve())中的每個任務來限制對其記憶體內容的訪問。

限制文件系統與設備訪問可以透過使用[chroot](https://en.wikipedia.org/wiki/Chroot)，[jail](https://en.wikipedia.org/wiki/FreeBSD_jail)，[sandboxing](https://en.wikipedia.org/wiki/Sandbox_(computer_security))，virtual machines，或像是透過平台或其它軟體啟用的其它機制來完成。

也注意到，Worker內執行的任何任務都有著與執行電腦相同的網路存取權限。如果Worker位於內網，那建議在防火牆outbound traffic(對外流量？)加入規則。
### Serializers
從version 4.0開始的預設序列化是JSON，但是由於它只支援一組受限制的類型，因此你可能會考慮想用pickle來替代。

以pickle來序列化是方便的，它可以序列化幾乎所有Python的物件，甚至是一些工作函數，但基於相同的原因，pickle本質上是不安全的，所以不論是不受信任的用戶端或未經身份驗證的時候，都應該避免使用。

你可以通過在[accept_content](https://docs.celeryq.dev/en/master/userguide/configuration.html#std-setting-accept_content)設置中指定接受的內容類型的白名單來禁用不受信任的內容：

*New in version 3.0.18.*
:::info
**Note:**

這個設置最早支援於3.0.18。如果你的執行版本是更早的，那設置會被忽略，因此確認你的執行版本是支援這設置的。
:::

```python
accept_content = ['json']
```
這接受序列化的名稱與內容類型的清單，因此你還可以為json指定內容類型：
```python
accept_content = ['application/json']
```

Celery還自帶一個特別的`auth serializer`(身份驗證序列化程式？)，它可以驗證Celery的client與workers之間的通信，確保訊息來自可信任的來源。使用Public-key cryptography(公鑰加密技術)，`auth serializer`可以驗證發送人員的真實性，要啟用這設置，請閱讀[Message Signing](http://docs.celeryproject.org/en/master/userguide/security.html#message-signinghttps://docs.celeryq.dev/en/master/userguide/security.html#message-signing)以取得更多資訊。
### Message Signing
Celery可以用套件[cryptograhpy](https://pypi.org/project/cryptography/)使用公鑰加密對訊息做簽章，client端發送的訊息使用私鑰，然後Worker用公鑰驗證。

最好的憑證應該是由正式的[憑證授權](https://en.wikipedia.org/wiki/Certificate_authority)單位來簽章，但它們也可以自簽章。

要啟用這個，你應該配置[task_serializer](https://docs.celeryq.dev/en/master/userguide/configuration.html#std-setting-task_serializer)設置來使用`auth serializer`。要強制Worker只能接收簽章訊息，你應該設置accept_content為['auth']。更進一步的事件協議簽章，將event_serializer設置為auth。還需要配置用於文件系統上的私鑰與憑證路徑，分別設置：[security_key](https://docs.celeryq.dev/en/master/userguide/security.html)、[security_certificate](https://docs.celeryq.dev/en/master/userguide/configuration.html#std-setting-security_certificate)、[security_cert_store](https://docs.celeryq.dev/en/master/userguide/configuration.html#std-setting-security_cert_store)。你可以用[security_digets](https://docs.celeryq.dev/en/master/userguide/configuration.html#std-setting-security_digest)來調整簽章演算法。如果使用加密的私鑰，那你可以用[security_key_password](https://docs.celeryq.dev/en/master/userguide/configuration.html#std-setting-security_key_password)來配置密碼。

上面配置好了以後，你還需要呼叫函數**celery.setup_security()**。注意到，這將禁用所有不安全的序列化程式，這樣Worker就不會接收到不受信任內容類型的訊息。

下面是一個使用`auth serializer`的配置範例，它的私鑰與憑證檔案位於`/etc/ssl`
```python
app = Celery()
app.conf.update(
    security_key='/etc/ssl/private/worker.key'
    security_certificate='/etc/ssl/certs/worker.pem'
    security_cert_store='/etc/ssl/certs/*.pem',
    security_digest='sha256',
    task_serializer='auth',
    event_serializer='auth',
    accept_content=['auth']
)
app.setup_security()
```

:::info
**Note:**

雖然不允許使用相對路徑，不過我們還是建議使用絕對路徑。

也注意到，`auth serializer`並不會對訊息的內容加密，如果需要，那你就要單獨的啟用它。
:::

### Intrusion Detection
在保護系統對抗入侵者攻擊時，最重要的部分是能夠檢測系統是否已經遭到破壞。
#### Logs
日誌通常是尋找安全漏洞的第一個地方，但是，如果日誌是可以被篡改的話，那就沒有用了。

一個好的解決方案就是設置專用的日誌伺服器來集中日誌。應該禁止對日誌伺服器的存取。除了將所有的日誌集中在一個地方，如果配置正確，它可以讓入侵人員更難篡改你的日誌。

使用syslog應該是相對簡單的設置(參考[syslog-ng](https://en.wikipedia.org/wiki/Syslog-ng)與[rsyslog](http://www.rsyslog.com/))。Celery使用套件[logging](https://docs.python.org/dev/library/logging.html#module-logging)，並且已經支援使用syslog。

一個瘋狂的技巧，就是使用UDP發送日誌並且切斷日誌記錄伺服器網路電纜的傳輸部分：-）。
#### Tripwire
[Tripwire](http://tripwire.com/)(現在是商業性質)是一個資料完整性工具，有幾個開源實作，用於文件系統中保持文件的[密碼雜湊](http://terms.naer.edu.tw/detail/2354160/)(cryptographic hashes)，因此當它們被改變的時候，系統管理員會收到警示通知。這樣的做法，當損失已經造成，系統已經被攻擊，你可以確切的知道那些文件被入侵者改變(password files、logs、back-doors、root-kits、…等等)。通常這是你偵測到入侵的唯一方法。

一些開源實作包含：
* [OSSEC](http://www.ossec.net/)
* [Samhain](http://la-samhna.de/samhain/index.html)
* [Open Source Tripwire](https://sourceforge.net/projects/tripwire/)
* [AIDE](http://aide.sourceforge.net/)

此外，[ZFS](https://en.wikipedia.org/wiki/ZFS)文件系統自帶內建完整性檢核可用。
##### Footnotes
https://blog.nelhage.com/2011/03/exploiting-pickle/
## History
20190903_依據4.4版本說明翻譯
20220520_依據5.2版本說明翻譯