mirror of
https://github.com/nocobase/nocobase.git
synced 2026-08-28 17:43:07 +08:00
fix(plugin-file-manager): active content upload (#10021)
* fix(plugin-file-manager): reject disallowed active content filenames * fix(plugin-file-manager): add trim before check
This commit is contained in:
@@ -15,6 +15,8 @@ keywords: "本地存储,Local Storage,服务器硬盘,存储路径,文件存储,
|
||||
|
||||
如果需要保存合同、证件、内部资料等不应公开的文件,请使用支持私有访问的 [S3 Pro](./s3-pro) 存储引擎。已有历史文件时,可参考[迁移到 S3 Pro](./migrate-to-s3-pro.md)。
|
||||
|
||||
如果你没有使用 Docker 或官方 nginx 配置,而是通过自定义 proxy 访问本地上传文件,请确认 `/storage/uploads/` 路径配置了 `X-Content-Type-Options: nosniff`,并让 `html`、`svg`、`xhtml`、`pdf` 等主动内容文件以附件方式下载。详细说明见[安全指南:文件存储](../../security/guide.md#文件存储)。
|
||||
|
||||
:::
|
||||
|
||||
## 配置参数
|
||||
|
||||
@@ -198,7 +198,30 @@ NocoBase 的用户密码使用 scrypt 算法加密后存储,可以有效对抗
|
||||
|
||||

|
||||
|
||||
对于本地存储或其他可通过应用同源 URL 直接访问的 public 存储,还需要额外注意“主动内容文件”带来的风险。例如 `html`、`xhtml`、`svg` 等文件可能在浏览器中被直接解析和执行。如果攻击者能够上传此类文件,并诱导用户打开文件链接,就可能借助应用的可信域名承载恶意页面或脚本。
|
||||
对于本地存储或其他可通过应用同源 URL 直接访问的 public 存储,还需要额外注意“主动内容文件”带来的风险。比如 `html`、`xhtml`、`svg` 等文件可能在浏览器中被直接解析和执行。如果攻击者能够上传此类文件,并诱导用户打开文件链接,就可能借助应用的可信域名承载恶意页面或脚本。
|
||||
|
||||
NocoBase 的上传校验不会信任请求中的 `Content-Type`,而是优先使用服务端检测到的 MIME type 进行判断。文件扩展名只表示文件名,不应被视为文件内容的权威类型。因此,处理 public 上传文件时,还需要确保文件访问链路本身具备安全响应头。
|
||||
|
||||
如果使用 Docker 部署,或使用 NocoBase 官方生成的 nginx 配置,上传目录已经包含这类保护:所有上传文件会返回 `X-Content-Type-Options: nosniff`,`html`、`xhtml`、`svg`、`svgz`、`pdf` 等主动内容文件会通过 `Content-Disposition: attachment` 作为下载内容返回。
|
||||
|
||||
如果你使用自定义 proxy、CDN、对象存储,或直接暴露本地上传目录,需要确认这些规则没有被绕过。可以参考下面的 nginx 配置:
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
如果你的 NocoBase 配置了 `APP_PUBLIC_PATH`,需要把上面的 `/storage/uploads/` 替换成实际的访问前缀,比如 `/nocobase/storage/uploads/`。
|
||||
|
||||
通常情况下,我们建议管理员:
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ Lokaler Speicher unterstützt keinen privaten Zugriff. Nach dem Hochladen erzeug
|
||||
|
||||
Wenn Sie Verträge, Ausweisdokumente, interne Unterlagen oder andere nicht öffentliche Dateien speichern müssen, verwenden Sie [S3 Pro](./s3-pro). Wenn bereits historische Dateien vorhanden sind, lesen Sie [Migration zu S3 Pro](./migrate-to-s3-pro.md).
|
||||
|
||||
Wenn Sie weder Docker noch die offizielle nginx-Konfiguration verwenden und lokale Upload-Dateien über einen benutzerdefinierten Proxy ausliefern, stellen Sie sicher, dass der Pfad `/storage/uploads/` `X-Content-Type-Options: nosniff` setzt und aktive Inhaltsdateien wie `html`, `svg`, `xhtml` und `pdf` als Anhänge zurückgibt. Details finden Sie im [Sicherheitsleitfaden: Dateispeicherung](../../security/guide.md).
|
||||
|
||||
:::
|
||||
|
||||
## Konfigurationsparameter
|
||||
@@ -24,4 +26,4 @@ Dieser Abschnitt stellt nur die spezifischen Parameter der lokalen Speicher-Engi
|
||||
Der Pfad repräsentiert sowohl den relativen Pfad für die Dateispeicherung auf dem Server als auch den URL-Zugriffspfad. Zum Beispiel steht „`user/avatar`“ (ohne führende oder abschließende Schrägstriche „`/`“) für:
|
||||
|
||||
1. Der relative Pfad auf dem Server, unter dem hochgeladene Dateien gespeichert werden: `/path/to/nocobase-app/storage/uploads/user/avatar`.
|
||||
2. Das URL-Präfix für den Zugriff auf die Dateien: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
2. Das URL-Präfix für den Zugriff auf die Dateien: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
|
||||
@@ -198,6 +198,29 @@ Wenn Sie sensible Dateien speichern müssen, empfehlen wir Cloud-Storage mit S3-
|
||||
|
||||
Bei lokalem Speicher oder anderem öffentlichen Speicher, der direkt über gleich-originäre Anwendungs-URLs erreichbar ist, sollten Sie zusätzlich auf die Risiken durch aktive Inhaltsdateien achten. Dateien wie `html`, `xhtml` und `svg` können vom Browser direkt geparst und ausgeführt werden. Wenn ein Angreifer solche Dateien hochladen und Benutzer zum Öffnen verleiten kann, kann er die vertrauenswürdige Domain Ihrer Anwendung zum Hosten bösartiger Seiten oder Skripte missbrauchen.
|
||||
|
||||
Die Upload-Prüfung von NocoBase vertraut nicht dem vom Request gesendeten `Content-Type`, sondern bevorzugt den serverseitig erkannten MIME type. Eine Dateierweiterung beschreibt nur den Dateinamen und sollte nicht als verlässlicher Inhaltstyp behandelt werden. Daher muss beim Ausliefern öffentlich zugänglicher Upload-Dateien auch der Zugriffspfad selbst passende Sicherheits-Header setzen.
|
||||
|
||||
Wenn Sie Docker verwenden oder die von NocoBase generierte nginx-Konfiguration einsetzen, enthält das Upload-Verzeichnis diese Schutzmaßnahmen bereits: Alle hochgeladenen Dateien geben `X-Content-Type-Options: nosniff` zurück, und aktive Inhaltsdateien wie `html`, `xhtml`, `svg`, `svgz` und `pdf` werden über `Content-Disposition: attachment` als Downloads zurückgegeben.
|
||||
|
||||
Wenn Sie einen benutzerdefinierten Proxy, CDN, Objektspeicher verwenden oder das lokale Upload-Verzeichnis direkt freigeben, stellen Sie sicher, dass diese Regeln nicht umgangen werden. Die folgende nginx-Konfiguration kann als Referenz dienen:
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
Wenn Ihre NocoBase-Anwendung `APP_PUBLIC_PATH` verwendet, ersetzen Sie `/storage/uploads/` durch das tatsächliche Zugriffsprefix, zum Beispiel `/nocobase/storage/uploads/`.
|
||||
|
||||
In der Regel empfehlen wir Administratoren:
|
||||
|
||||
- Bevorzugen Sie privaten Speicher, signierte URLs oder eine separate Dateidomain, damit hochgeladene Dateien nicht direkt unter derselben Origin wie die Hauptanwendung ausgeliefert werden.
|
||||
|
||||
@@ -9,6 +9,8 @@ Local Storage does not support private access. After a file is uploaded, NocoBas
|
||||
|
||||
If you need to store contracts, identity documents, internal materials, or other files that should not be public, use [S3 Pro](./s3-pro). If historical files already exist, see [Migrate to S3 Pro](./migrate-to-s3-pro.md).
|
||||
|
||||
If you are not using Docker or the official nginx configuration and access local uploaded files through a custom proxy, make sure the `/storage/uploads/` path sets `X-Content-Type-Options: nosniff` and returns active content files such as `html`, `svg`, `xhtml`, and `pdf` as attachments. For details, see [Security guide: File storage](../../security/guide.md#file-storage).
|
||||
|
||||
:::
|
||||
|
||||
## Configuration Parameters
|
||||
@@ -26,4 +28,4 @@ This section only introduces parameters specific to the local storage engine. Fo
|
||||
Represents both the relative path for file storage on the server and the URL access path. For example, "`user/avatar`" (without leading or trailing slashes) represents:
|
||||
|
||||
1. The relative path on the server where uploaded files are stored: `/path/to/nocobase-app/storage/uploads/user/avatar`.
|
||||
2. The URL prefix for accessing the files: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
2. The URL prefix for accessing the files: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
|
||||
@@ -215,6 +215,29 @@ If you need to store sensitive files, it is recommended to use a cloud storage s
|
||||
|
||||
For local storage or other public storage that can be accessed directly through same-origin application URLs, you should also pay extra attention to the risks introduced by active content files. Files such as `html`, `xhtml`, and `svg` may be parsed and executed directly by the browser. If an attacker can upload such a file and trick a user into opening it, the attacker may use your trusted application domain to host a malicious page or script.
|
||||
|
||||
NocoBase upload validation does not trust the `Content-Type` sent by the request. It prefers the MIME type detected on the server side. A file extension only represents the filename and should not be treated as the authoritative file content type. Therefore, when serving public uploaded files, you also need to make sure the file access path has proper security response headers.
|
||||
|
||||
If you deploy with Docker or use the nginx configuration generated by NocoBase, the upload directory already includes this protection: all uploaded files return `X-Content-Type-Options: nosniff`, and active content files such as `html`, `xhtml`, `svg`, `svgz`, and `pdf` are returned as downloads through `Content-Disposition: attachment`.
|
||||
|
||||
If you use a custom proxy, CDN, object storage, or expose the local upload directory directly, make sure these rules are not bypassed. You can use the following nginx configuration as a reference:
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
If your NocoBase app uses `APP_PUBLIC_PATH`, replace `/storage/uploads/` with the actual access prefix, such as `/nocobase/storage/uploads/`.
|
||||
|
||||
In most cases, we recommend that administrators:
|
||||
|
||||
- Prefer private storage, signed URLs, or a separate file domain, so that user-uploaded files are not served directly from the same origin as the main application.
|
||||
|
||||
@@ -9,6 +9,8 @@ El almacenamiento local no admite acceso privado. Después de subir un archivo,
|
||||
|
||||
Si necesita guardar contratos, documentos de identidad, materiales internos u otros archivos que no deben ser públicos, utilice [S3 Pro](./s3-pro). Si ya existen archivos históricos, consulte [Migrar a S3 Pro](./migrate-to-s3-pro.md).
|
||||
|
||||
Si no utiliza Docker ni la configuración oficial de nginx y accede a los archivos locales subidos mediante un proxy personalizado, asegúrese de que la ruta `/storage/uploads/` configure `X-Content-Type-Options: nosniff` y devuelva archivos de contenido activo como `html`, `svg`, `xhtml` y `pdf` como adjuntos. Para más detalles, consulte la [guía de seguridad: almacenamiento de archivos](../../security/guide.md).
|
||||
|
||||
:::
|
||||
|
||||
## Parámetros de Configuración
|
||||
@@ -24,4 +26,4 @@ Aquí solo se presentan los parámetros específicos del motor de almacenamiento
|
||||
Representa tanto la ruta relativa donde se almacenan los archivos en el servidor como la ruta de acceso URL. Por ejemplo, "`user/avatar`" (sin barras diagonales al inicio ni al final) representa:
|
||||
|
||||
1. La ruta relativa en el servidor donde se guardan los archivos subidos: `/path/to/nocobase-app/storage/uploads/user/avatar`.
|
||||
2. El prefijo de la URL para acceder a los archivos: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
2. El prefijo de la URL para acceder a los archivos: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
|
||||
@@ -194,6 +194,29 @@ Si necesita almacenar archivos sensibles, se recomienda utilizar un servicio de
|
||||
|
||||
Para el almacenamiento local u otro almacenamiento público accesible directamente mediante URLs del mismo origen que la aplicación, también debe prestar especial atención a los riesgos introducidos por archivos con contenido activo. Archivos como `html`, `xhtml` y `svg` pueden ser interpretados y ejecutados directamente por el navegador. Si un atacante puede subir uno de estos archivos y engañar a un usuario para que lo abra, podría usar el dominio de confianza de su aplicación para alojar una página o script malicioso.
|
||||
|
||||
La validación de cargas de NocoBase no confía en el `Content-Type` enviado por la solicitud, sino que prefiere el MIME type detectado en el servidor. La extensión de un archivo solo representa el nombre del archivo y no debe tratarse como el tipo de contenido autorizado. Por lo tanto, al servir archivos subidos públicamente, también debe asegurarse de que la ruta de acceso a los archivos tenga los encabezados de seguridad adecuados.
|
||||
|
||||
Si despliega con Docker o utiliza la configuración nginx generada por NocoBase, el directorio de cargas ya incluye esta protección: todos los archivos subidos devuelven `X-Content-Type-Options: nosniff`, y los archivos con contenido activo como `html`, `xhtml`, `svg`, `svgz` y `pdf` se devuelven como descargas mediante `Content-Disposition: attachment`.
|
||||
|
||||
Si utiliza un proxy personalizado, CDN, almacenamiento de objetos o expone directamente el directorio local de cargas, asegúrese de que estas reglas no se omitan. Puede usar la siguiente configuración nginx como referencia:
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
Si su aplicación NocoBase usa `APP_PUBLIC_PATH`, reemplace `/storage/uploads/` por el prefijo de acceso real, como `/nocobase/storage/uploads/`.
|
||||
|
||||
Normalmente recomendamos a los administradores:
|
||||
|
||||
- Priorizar almacenamiento privado, URLs firmadas o un dominio independiente para archivos, de modo que los archivos subidos por los usuarios no se sirvan directamente desde el mismo origen que la aplicación principal.
|
||||
|
||||
@@ -9,6 +9,8 @@ Le stockage local ne prend pas en charge l’accès privé. Après l’envoi d
|
||||
|
||||
Si vous devez stocker des contrats, pièces d’identité, documents internes ou autres fichiers non publics, utilisez [S3 Pro](./s3-pro). Si des fichiers historiques existent déjà, consultez [Migrer vers S3 Pro](./migrate-to-s3-pro.md).
|
||||
|
||||
Si vous n’utilisez pas Docker ni la configuration nginx officielle, et que vous accédez aux fichiers locaux téléversés via un proxy personnalisé, assurez-vous que le chemin `/storage/uploads/` définit `X-Content-Type-Options: nosniff` et renvoie les fichiers de contenu actif comme `html`, `svg`, `xhtml` et `pdf` en tant que pièces jointes. Pour plus de détails, consultez le [guide de sécurité : stockage de fichiers](../../security/guide.md).
|
||||
|
||||
:::
|
||||
|
||||
## Paramètres de configuration
|
||||
@@ -24,4 +26,4 @@ Cette section présente uniquement les paramètres spécifiques au moteur de sto
|
||||
Il représente à la fois le chemin relatif de stockage des fichiers sur le serveur et le chemin d'accès via URL. Par exemple, « `user/avatar` » (sans les barres obliques au début et à la fin) représente :
|
||||
|
||||
1. Le chemin relatif sur le serveur où les fichiers téléchargés sont stockés : `/path/to/nocobase-app/storage/uploads/user/avatar`.
|
||||
2. Le préfixe d'adresse URL pour accéder aux fichiers : `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
2. Le préfixe d'adresse URL pour accéder aux fichiers : `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
|
||||
@@ -198,6 +198,29 @@ Pour stocker des fichiers sensibles, nous recommandons un service de stockage cl
|
||||
|
||||
Pour le stockage local ou tout autre stockage public accessible directement via des URL de même origine que l'application, il faut également prêter une attention particulière aux risques liés aux fichiers contenant du contenu actif. Des fichiers tels que `html`, `xhtml` et `svg` peuvent être analysés et exécutés directement par le navigateur. Si un attaquant peut téléverser un tel fichier et inciter un utilisateur à l'ouvrir, il peut utiliser le domaine de confiance de votre application pour héberger une page ou un script malveillant.
|
||||
|
||||
La validation des téléversements par NocoBase ne fait pas confiance au `Content-Type` envoyé par la requête. Elle privilégie le MIME type détecté côté serveur. Une extension de fichier ne représente que le nom du fichier et ne doit pas être considérée comme le type de contenu faisant autorité. Ainsi, lorsque vous servez des fichiers téléversés publics, vous devez aussi vous assurer que le chemin d’accès aux fichiers dispose des en-têtes de sécurité appropriés.
|
||||
|
||||
Si vous déployez avec Docker ou utilisez la configuration nginx générée par NocoBase, le répertoire de téléversement inclut déjà cette protection : tous les fichiers téléversés renvoient `X-Content-Type-Options: nosniff`, et les fichiers de contenu actif comme `html`, `xhtml`, `svg`, `svgz` et `pdf` sont renvoyés comme téléchargements via `Content-Disposition: attachment`.
|
||||
|
||||
Si vous utilisez un proxy personnalisé, un CDN, un stockage objet, ou si vous exposez directement le répertoire local de téléversement, assurez-vous que ces règles ne sont pas contournées. Vous pouvez utiliser la configuration nginx suivante comme référence :
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
Si votre application NocoBase utilise `APP_PUBLIC_PATH`, remplacez `/storage/uploads/` par le préfixe d’accès réel, par exemple `/nocobase/storage/uploads/`.
|
||||
|
||||
En règle générale, nous recommandons aux administrateurs de :
|
||||
|
||||
- Privilégier le stockage privé, les URL signées ou un domaine de fichiers distinct, afin que les fichiers téléversés ne soient pas servis directement depuis la même origine que l'application principale.
|
||||
|
||||
@@ -16,6 +16,8 @@ Local Storage tidak mendukung akses privat. Setelah file di-upload, NocoBase mem
|
||||
|
||||
Jika perlu menyimpan kontrak, dokumen identitas, materi internal, atau file lain yang tidak boleh publik, gunakan [S3 Pro](./s3-pro). Jika file historis sudah ada, lihat [Migrasi ke S3 Pro](./migrate-to-s3-pro.md).
|
||||
|
||||
Jika tidak menggunakan Docker atau konfigurasi nginx resmi, dan mengakses file upload lokal melalui proxy kustom, pastikan path `/storage/uploads/` mengatur `X-Content-Type-Options: nosniff` dan mengembalikan file active content seperti `html`, `svg`, `xhtml`, dan `pdf` sebagai attachment. Untuk detail, lihat [panduan keamanan: File Storage](../../security/guide.md).
|
||||
|
||||
:::
|
||||
|
||||
## Parameter Konfigurasi
|
||||
|
||||
@@ -198,6 +198,41 @@ Jika perlu menyimpan file sensitif, disarankan menggunakan layanan cloud storage
|
||||
|
||||

|
||||
|
||||
Untuk local storage atau public storage lain yang dapat diakses langsung melalui URL same-origin aplikasi, Anda juga perlu memperhatikan risiko dari file active content. File seperti `html`, `xhtml`, dan `svg` dapat diparse dan dijalankan langsung oleh browser. Jika penyerang dapat mengupload file seperti ini dan membuat user membukanya, penyerang dapat menggunakan domain aplikasi tepercaya untuk menghosting halaman atau script berbahaya.
|
||||
|
||||
Validasi upload NocoBase tidak mempercayai `Content-Type` yang dikirim request. Validasi ini mengutamakan MIME type yang dideteksi di sisi server. Ekstensi file hanya merepresentasikan nama file dan tidak boleh dianggap sebagai tipe konten yang otoritatif. Karena itu, saat menyajikan file upload publik, Anda juga perlu memastikan jalur akses file memiliki header respons keamanan yang tepat.
|
||||
|
||||
Jika Anda melakukan deployment dengan Docker atau menggunakan konfigurasi nginx yang dibuat oleh NocoBase, direktori upload sudah menyertakan perlindungan ini: semua file upload mengembalikan `X-Content-Type-Options: nosniff`, dan file active content seperti `html`, `xhtml`, `svg`, `svgz`, dan `pdf` dikembalikan sebagai download melalui `Content-Disposition: attachment`.
|
||||
|
||||
Jika menggunakan proxy kustom, CDN, object storage, atau mengekspos direktori upload lokal secara langsung, pastikan aturan ini tidak dilewati. Anda dapat menggunakan konfigurasi nginx berikut sebagai referensi:
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
Jika aplikasi NocoBase Anda menggunakan `APP_PUBLIC_PATH`, ganti `/storage/uploads/` dengan prefix akses aktual, seperti `/nocobase/storage/uploads/`.
|
||||
|
||||
Umumnya, kami merekomendasikan administrator untuk:
|
||||
|
||||
- Mengutamakan private storage, signed URL, atau domain file terpisah, agar file yang diupload user tidak disajikan langsung dari origin yang sama dengan aplikasi utama.
|
||||
- Menerapkan allowlist MIME type yang ketat untuk upload dan hanya mengizinkan tipe file yang benar-benar dibutuhkan bisnis.
|
||||
- Berhati-hati saat mengizinkan active content type seperti `text/html`, `application/xhtml+xml`, dan `image/svg+xml`. Meskipun sistem mencoba mengembalikan file ini sebagai download, hal ini tidak boleh dianggap sebagai pengganti penuh untuk pembatasan upload dan isolasi origin.
|
||||
- Menerapkan pengaturan keamanan yang konsisten pada reverse proxy, CDN, object storage, dan layer distribusi file statis lainnya, agar file berbahaya tidak dikembalikan inline dengan melewati perlindungan application layer.
|
||||
- Jangan gunakan local/public storage untuk menghosting konten Web yang tidak tepercaya. Jika kemampuan ini benar-benar diperlukan, gunakan domain terisolasi dan evaluasi CSP, perilaku download, dan access control secara terpisah.
|
||||
|
||||
Jika administrator secara eksplisit mengizinkan upload tipe file berbahaya, administrator perlu mengevaluasi sendiri risiko phishing, eksekusi script same-origin, dan kebocoran informasi sensitif, serta memastikan Web Server, gateway, CDN, dan layanan storage dalam rantai deployment menerapkan pembatasan yang konsisten.
|
||||
|
||||
### Backup Aplikasi
|
||||
|
||||
Untuk memastikan keamanan data aplikasi dan menghindari kehilangan data, kami merekomendasikan Anda untuk membackup database secara berkala.
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
契約書、身分証明書、社内資料など公開すべきでないファイルを保存する場合は、[S3 Pro](./s3-pro) を使用してください。既存ファイルがある場合は、[S3 Pro への移行](./migrate-to-s3-pro.md)を参照してください。
|
||||
|
||||
Docker または公式の nginx 設定を使用せず、カスタム proxy 経由でローカルアップロードファイルにアクセスする場合は、`/storage/uploads/` パスで `X-Content-Type-Options: nosniff` を設定し、`html`、`svg`、`xhtml`、`pdf` などのアクティブコンテンツファイルを添付ファイルとして返すようにしてください。詳細は [セキュリティガイド:ファイルストレージ](../../security/guide.md)を参照してください。
|
||||
|
||||
:::
|
||||
|
||||
## 設定パラメーター
|
||||
@@ -24,4 +26,4 @@
|
||||
サーバー上でのファイル保存の相対パスとURLアクセスパスの両方を表します。例えば、「`user/avatar`」(先頭と末尾の「`/`」は不要です)は、以下を表します。
|
||||
|
||||
1. アップロードファイルがサーバーに保存される相対パス:`/path/to/nocobase-app/storage/uploads/user/avatar`。
|
||||
2. ファイルにアクセスする際のURLプレフィックス:`http://localhost:13000/storage/uploads/user/avatar`。
|
||||
2. ファイルにアクセスする際のURLプレフィックス:`http://localhost:13000/storage/uploads/user/avatar`。
|
||||
|
||||
@@ -194,6 +194,29 @@ NocoBaseでサードパーティサービスを使用する際、サードパー
|
||||
|
||||
ローカルストレージや、アプリケーションと同一オリジンの URL で直接アクセスできる public ストレージについては、アクティブコンテンツを含むファイルのリスクにも注意が必要です。`html`、`xhtml`、`svg` などのファイルは、ブラウザによって直接解析・実行される可能性があります。攻撃者がこのようなファイルをアップロードし、ユーザーに開かせることができる場合、信頼されたアプリケーションドメイン上で悪意のあるページやスクリプトを配信できるおそれがあります。
|
||||
|
||||
NocoBase のアップロード検証は、リクエストで送信された `Content-Type` を信頼せず、サーバー側で検出した MIME type を優先します。ファイル拡張子はファイル名を表すだけであり、ファイル内容の権威あるタイプとして扱うべきではありません。そのため、public なアップロードファイルを配信する場合は、ファイルアクセス経路自体にも適切なセキュリティレスポンスヘッダーが必要です。
|
||||
|
||||
Docker でデプロイしている場合、または NocoBase が生成した nginx 設定を使用している場合、アップロードディレクトリにはすでにこの保護が含まれています。すべてのアップロードファイルは `X-Content-Type-Options: nosniff` を返し、`html`、`xhtml`、`svg`、`svgz`、`pdf` などのアクティブコンテンツファイルは `Content-Disposition: attachment` によりダウンロードとして返されます。
|
||||
|
||||
カスタム proxy、CDN、オブジェクトストレージを使用する場合、またはローカルアップロードディレクトリを直接公開する場合は、これらのルールが迂回されないようにしてください。次の nginx 設定を参考にできます。
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
NocoBase アプリで `APP_PUBLIC_PATH` を設定している場合は、`/storage/uploads/` を実際のアクセスプレフィックス(例:`/nocobase/storage/uploads/`)に置き換えてください。
|
||||
|
||||
通常、管理者には次の対応を推奨します。
|
||||
|
||||
- ユーザーアップロードファイルがメインアプリケーションと同一オリジンで直接配信されないよう、プライベートストレージ、署名付き URL、または独立したファイル用ドメインを優先してください。
|
||||
|
||||
@@ -9,6 +9,8 @@ O armazenamento local não oferece acesso privado. Depois que um arquivo é envi
|
||||
|
||||
Se você precisa armazenar contratos, documentos de identidade, materiais internos ou outros arquivos que não devem ser públicos, use [S3 Pro](./s3-pro). Se já houver arquivos históricos, consulte [Migrar para S3 Pro](./migrate-to-s3-pro.md).
|
||||
|
||||
Se você não usa Docker nem a configuração oficial do nginx, e acessa arquivos locais enviados por meio de um proxy personalizado, confirme que o caminho `/storage/uploads/` define `X-Content-Type-Options: nosniff` e retorna arquivos com conteúdo ativo, como `html`, `svg`, `xhtml` e `pdf`, como anexos. Para mais detalhes, consulte o [guia de segurança: armazenamento de arquivos](../../security/guide.md).
|
||||
|
||||
:::
|
||||
|
||||
## Parâmetros de Configuração
|
||||
@@ -24,4 +26,4 @@ Esta seção apresenta apenas os parâmetros específicos do motor de armazename
|
||||
Representa tanto o caminho relativo para o armazenamento de arquivos no servidor quanto o caminho de acesso via URL. Por exemplo, "`user/avatar`" (sem barras iniciais ou finais) representa:
|
||||
|
||||
1. O caminho relativo no servidor onde os arquivos enviados são armazenados: `/path/to/nocobase-app/storage/uploads/user/avatar`.
|
||||
2. O prefixo da URL para acessar os arquivos: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
2. O prefixo da URL para acessar os arquivos: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
|
||||
@@ -24,6 +24,29 @@ Se precisar armazenar arquivos sensíveis, é recomendável usar um serviço de
|
||||
|
||||
Para armazenamento local ou outro armazenamento público acessível diretamente por URLs da aplicação no mesmo domínio de origem, também é necessário prestar atenção extra aos riscos trazidos por arquivos com conteúdo ativo. Arquivos como `html`, `xhtml` e `svg` podem ser interpretados e executados diretamente pelo navegador. Se um invasor conseguir enviar esse tipo de arquivo e induzir um usuário a abri-lo, poderá usar o domínio confiável da sua aplicação para hospedar uma página ou script malicioso.
|
||||
|
||||
A validação de upload do NocoBase não confia no `Content-Type` enviado pela requisição. Ela prioriza o MIME type detectado no lado do servidor. A extensão do arquivo representa apenas o nome do arquivo e não deve ser tratada como o tipo de conteúdo autoritativo. Portanto, ao servir arquivos enviados publicamente, também é necessário garantir que o caminho de acesso aos arquivos tenha os cabeçalhos de segurança adequados.
|
||||
|
||||
Se você fizer o deploy com Docker ou usar a configuração nginx gerada pelo NocoBase, o diretório de uploads já inclui essa proteção: todos os arquivos enviados retornam `X-Content-Type-Options: nosniff`, e arquivos com conteúdo ativo, como `html`, `xhtml`, `svg`, `svgz` e `pdf`, são retornados como downloads por meio de `Content-Disposition: attachment`.
|
||||
|
||||
Se você usa um proxy personalizado, CDN, armazenamento de objetos ou expõe diretamente o diretório local de uploads, certifique-se de que essas regras não sejam contornadas. Você pode usar a configuração nginx abaixo como referência:
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
Se o seu aplicativo NocoBase usa `APP_PUBLIC_PATH`, substitua `/storage/uploads/` pelo prefixo real de acesso, como `/nocobase/storage/uploads/`.
|
||||
|
||||
Em geral, recomendamos que os administradores:
|
||||
|
||||
- Priorizem armazenamento privado, URLs assinadas ou um domínio separado para arquivos, para evitar que arquivos enviados por usuários sejam servidos diretamente a partir da mesma origem da aplicação principal.
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
Если нужно хранить договоры, документы, внутренние материалы или другие непубличные файлы, используйте [S3 Pro](./s3-pro). Если исторические файлы уже есть, см. [Миграция на S3 Pro](./migrate-to-s3-pro.md).
|
||||
|
||||
Если вы не используете Docker или официальную конфигурацию nginx, а раздаете локально загруженные файлы через собственный proxy, убедитесь, что путь `/storage/uploads/` задает `X-Content-Type-Options: nosniff` и возвращает файлы с активным содержимым, такие как `html`, `svg`, `xhtml` и `pdf`, как вложения. Подробнее см. в [руководстве по безопасности: хранение файлов](../../security/guide.md).
|
||||
|
||||
:::
|
||||
|
||||
## Параметры конфигурации
|
||||
@@ -24,4 +26,4 @@
|
||||
Этот параметр обозначает как относительный путь для хранения файлов на сервере, так и путь для доступа по URL. Например, "`user/avatar`" (без начальных и конечных символов "` / `" ) означает:
|
||||
|
||||
1. Относительный путь на сервере, где хранятся загруженные файлы: `/path/to/nocobase-app/storage/uploads/user/avatar`.
|
||||
2. Префикс URL-адреса для доступа к файлам: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
2. Префикс URL-адреса для доступа к файлам: `http://localhost:13000/storage/uploads/user/avatar`.
|
||||
|
||||
@@ -24,6 +24,29 @@ NocoBase поддерживает следующие политики безоп
|
||||
|
||||
Для локального хранилища или другого public-хранилища, доступного напрямую по URL того же источника, что и приложение, также необходимо учитывать риски, связанные с файлами с активным содержимым. Такие файлы, как `html`, `xhtml` и `svg`, могут быть напрямую интерпретированы и выполнены браузером. Если злоумышленник сможет загрузить такой файл и убедить пользователя открыть его, он сможет использовать доверенный домен приложения для размещения вредоносной страницы или скрипта.
|
||||
|
||||
Проверка загрузок в NocoBase не доверяет `Content-Type`, отправленному в запросе. Она предпочитает MIME type, определенный на стороне сервера. Расширение файла описывает только имя файла и не должно считаться авторитетным типом содержимого. Поэтому при раздаче public-загрузок также необходимо убедиться, что путь доступа к файлам задает корректные защитные HTTP-заголовки.
|
||||
|
||||
Если вы развертываете NocoBase через Docker или используете nginx-конфигурацию, сгенерированную NocoBase, каталог загрузок уже содержит эту защиту: все загруженные файлы возвращают `X-Content-Type-Options: nosniff`, а файлы с активным содержимым, такие как `html`, `xhtml`, `svg`, `svgz` и `pdf`, отдаются как скачиваемые файлы через `Content-Disposition: attachment`.
|
||||
|
||||
Если вы используете собственный proxy, CDN, объектное хранилище или напрямую публикуете локальный каталог загрузок, убедитесь, что эти правила нельзя обойти. В качестве ориентира можно использовать следующую конфигурацию nginx:
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
Если ваше приложение NocoBase использует `APP_PUBLIC_PATH`, замените `/storage/uploads/` фактическим префиксом доступа, например `/nocobase/storage/uploads/`.
|
||||
|
||||
Обычно мы рекомендуем администраторам:
|
||||
|
||||
- По возможности использовать приватное хранилище, подписанные URL или отдельный домен для файлов, чтобы пользовательские загрузки не отдавались напрямую с того же origin, что и основное приложение.
|
||||
|
||||
@@ -16,6 +16,8 @@ Local Storage không hỗ trợ truy cập riêng tư. Sau khi file được upl
|
||||
|
||||
Nếu cần lưu hợp đồng, giấy tờ định danh, tài liệu nội bộ hoặc các file không nên công khai, hãy dùng [S3 Pro](./s3-pro). Nếu đã có file lịch sử, hãy xem [Di chuyển sang S3 Pro](./migrate-to-s3-pro.md).
|
||||
|
||||
Nếu bạn không dùng Docker hoặc cấu hình nginx chính thức, mà truy cập file upload cục bộ thông qua proxy tùy chỉnh, hãy đảm bảo path `/storage/uploads/` thiết lập `X-Content-Type-Options: nosniff` và trả về các file active content như `html`, `svg`, `xhtml` và `pdf` dưới dạng attachment. Xem chi tiết tại [hướng dẫn bảo mật: lưu trữ file](../../security/guide.md).
|
||||
|
||||
:::
|
||||
|
||||
## Tham số cấu hình
|
||||
|
||||
@@ -198,6 +198,41 @@ Nếu có nhu cầu lưu trữ file nhạy cảm, khuyến nghị sử dụng d
|
||||
|
||||

|
||||
|
||||
Đối với Local Storage hoặc public storage khác có thể truy cập trực tiếp bằng URL cùng origin với ứng dụng, bạn cũng cần chú ý đến rủi ro từ file active content. Các file như `html`, `xhtml` và `svg` có thể được trình duyệt phân tích và thực thi trực tiếp. Nếu kẻ tấn công có thể upload loại file này và dụ người dùng mở file, họ có thể dùng domain tin cậy của ứng dụng để lưu trữ trang hoặc script độc hại.
|
||||
|
||||
Kiểm tra upload của NocoBase không tin `Content-Type` do request gửi lên, mà ưu tiên MIME type được phát hiện ở phía server. Phần mở rộng file chỉ thể hiện tên file và không nên được xem là kiểu nội dung có thẩm quyền. Vì vậy, khi phục vụ file upload công khai, bạn cũng cần đảm bảo đường dẫn truy cập file có các response header bảo mật phù hợp.
|
||||
|
||||
Nếu deploy bằng Docker hoặc dùng cấu hình nginx do NocoBase tạo, thư mục upload đã có các biện pháp bảo vệ này: mọi file upload đều trả về `X-Content-Type-Options: nosniff`, và các file active content như `html`, `xhtml`, `svg`, `svgz` và `pdf` được trả về dưới dạng download thông qua `Content-Disposition: attachment`.
|
||||
|
||||
Nếu dùng proxy tùy chỉnh, CDN, object storage, hoặc expose trực tiếp thư mục upload cục bộ, hãy đảm bảo các quy tắc này không bị bỏ qua. Bạn có thể tham khảo cấu hình nginx sau:
|
||||
|
||||
```nginx
|
||||
location ~* ^/storage/uploads/(.*\.(?:htm|html|svg|svgz|xhtml|pdf))$ {
|
||||
alias /path/to/nocobase/storage/uploads/$1;
|
||||
add_header Content-Disposition "attachment" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
|
||||
location /storage/uploads/ {
|
||||
alias /path/to/nocobase/storage/uploads/;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
autoindex off;
|
||||
}
|
||||
```
|
||||
|
||||
Nếu ứng dụng NocoBase của bạn cấu hình `APP_PUBLIC_PATH`, hãy thay `/storage/uploads/` bằng prefix truy cập thực tế, ví dụ `/nocobase/storage/uploads/`.
|
||||
|
||||
Thông thường, chúng tôi khuyến nghị admin:
|
||||
|
||||
- Ưu tiên private storage, signed URL, hoặc domain file độc lập, để file do người dùng upload không được phục vụ trực tiếp từ cùng origin với ứng dụng chính.
|
||||
- Áp dụng allowlist MIME type nghiêm ngặt cho upload và chỉ cho phép các loại file thực sự cần thiết cho nghiệp vụ.
|
||||
- Thận trọng khi cho phép các loại active content như `text/html`, `application/xhtml+xml` và `image/svg+xml`. Ngay cả khi hệ thống cố gắng trả về các file này dưới dạng download, điều đó không thể thay thế hoàn toàn giới hạn upload và cách ly origin.
|
||||
- Áp dụng cấu hình bảo mật nhất quán cho reverse proxy, CDN, object storage và mọi lớp phân phối file tĩnh khác, để tránh file nguy hiểm được trả về inline bằng cách bỏ qua bảo vệ ở application layer.
|
||||
- Không dùng local/public storage để host nội dung Web không đáng tin cậy. Nếu thực sự cần khả năng này, hãy dùng domain tách biệt và đánh giá riêng CSP, hành vi download và access control.
|
||||
|
||||
Nếu admin cho phép rõ ràng việc upload các loại file nguy hiểm, admin cần tự đánh giá rủi ro phishing, thực thi script cùng origin và rò rỉ thông tin nhạy cảm, đồng thời đảm bảo Web Server, gateway, CDN và dịch vụ storage trong toàn bộ chuỗi deployment áp dụng giới hạn nhất quán.
|
||||
|
||||
### Sao lưu ứng dụng
|
||||
|
||||
Để đảm bảo bảo mật dữ liệu ứng dụng, tránh mất dữ liệu, chúng tôi khuyến nghị bạn định kỳ sao lưu database.
|
||||
|
||||
@@ -355,6 +355,86 @@ describe('action', () => {
|
||||
expect(stats.size).toBe(255);
|
||||
});
|
||||
|
||||
it('rejects a forged image upload whose active content filename is not allowed', async () => {
|
||||
const imageStorage = await StorageRepo.create({
|
||||
values: {
|
||||
name: 'imageOnlyStorage',
|
||||
type: STORAGE_TYPE_LOCAL,
|
||||
baseUrl: DEFAULT_LOCAL_BASE_URL,
|
||||
rules: {
|
||||
mimetype: ['image/*'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
db.collection({
|
||||
name: 'customers',
|
||||
fields: [
|
||||
{
|
||||
name: 'avatar',
|
||||
type: 'belongsTo',
|
||||
target: 'attachments',
|
||||
storage: imageStorage.name,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const forgedHtml = Buffer.concat([
|
||||
Buffer.from([0xff, 0xd8, 0xff, 0xe0]),
|
||||
Buffer.from('ddddddddddddddddddd<img src=axxxx onerror="onerror=alert(1)" s>'),
|
||||
]);
|
||||
const response = await agent
|
||||
.post(`/attachments:create?${querystring.stringify({ attachmentField: 'customers.avatar' })}`)
|
||||
.attach(FILE_FIELD_NAME, forgedHtml, {
|
||||
filename: 'custom_name.html',
|
||||
contentType: 'image/jpeg',
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
});
|
||||
|
||||
it('allows a forged image upload when its active content filename is explicitly allowed', async () => {
|
||||
const imageStorage = await StorageRepo.create({
|
||||
values: {
|
||||
name: 'imageAndHtmlStorage',
|
||||
type: STORAGE_TYPE_LOCAL,
|
||||
baseUrl: DEFAULT_LOCAL_BASE_URL,
|
||||
rules: {
|
||||
mimetype: ['image/*', 'text/html'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
db.collection({
|
||||
name: 'customers',
|
||||
fields: [
|
||||
{
|
||||
name: 'avatar',
|
||||
type: 'belongsTo',
|
||||
target: 'attachments',
|
||||
storage: imageStorage.name,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const forgedHtml = Buffer.concat([
|
||||
Buffer.from([0xff, 0xd8, 0xff, 0xe0]),
|
||||
Buffer.from('ddddddddddddddddddd<img src=axxxx onerror="onerror=alert(1)" s>'),
|
||||
]);
|
||||
const response = await agent
|
||||
.post(`/attachments:create?${querystring.stringify({ attachmentField: 'customers.avatar' })}`)
|
||||
.attach(FILE_FIELD_NAME, forgedHtml, {
|
||||
filename: 'custom_name.html',
|
||||
contentType: 'image/jpeg',
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body.data).toMatchObject({
|
||||
extname: '.html',
|
||||
mimetype: 'image/jpeg',
|
||||
});
|
||||
});
|
||||
|
||||
it('upload to storage which is not default', async () => {
|
||||
const BASE_URL = `/storage/uploads/another`;
|
||||
const urlPath = 'test/path';
|
||||
|
||||
@@ -25,6 +25,25 @@ import {
|
||||
import { StorageClassType, StorageType } from '../storages';
|
||||
import { getDocumentRoot, normalizeLocalStoragePath, resolveSafePath } from '../storages/local';
|
||||
|
||||
const ACTIVE_CONTENT_MIMETYPES = new Set(['application/pdf', 'application/xhtml+xml', 'image/svg+xml', 'text/html']);
|
||||
|
||||
function matchesMimePattern(mimetype: string, pattern: string | string[] = '*') {
|
||||
const normalizedPattern = pattern.toString().trim();
|
||||
if (!normalizedPattern || normalizedPattern === '*') {
|
||||
return true;
|
||||
}
|
||||
return normalizedPattern
|
||||
.split(',')
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean)
|
||||
.some(match(mimetype));
|
||||
}
|
||||
|
||||
function isDisallowedActiveContentFilename(filename: string, pattern: string | string[] = '*') {
|
||||
const mimetype = mime.lookup(filename);
|
||||
return Boolean(mimetype && ACTIVE_CONTENT_MIMETYPES.has(mimetype) && !matchesMimePattern(mimetype, pattern));
|
||||
}
|
||||
|
||||
function makeMulterStorage(storage: StorageType) {
|
||||
const innerStorage = storage.make();
|
||||
|
||||
@@ -98,7 +117,11 @@ function makeMulterStorage(storage: StorageType) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!detectedMime || (pattern !== '*' && !pattern.toString().split(',').some(match(detectedMime)))) {
|
||||
if (
|
||||
!detectedMime ||
|
||||
!matchesMimePattern(detectedMime, pattern) ||
|
||||
isDisallowedActiveContentFilename(file.originalname, pattern)
|
||||
) {
|
||||
const err = new Error('Mime type not allowed by storage rule');
|
||||
err.name = 'MulterError';
|
||||
originalStream.destroy();
|
||||
|
||||
Reference in New Issue
Block a user