news 2026/10/22 12:09:46

doccano安全加固指南:SQL注入与XSS防护实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
doccano安全加固指南:SQL注入与XSS防护实战

做数据标注平台的部署和维护,最怕听到的一句话就是:“这个系统好像被人扫到了。”我接手过的数据标注项目里,doccano 出现的频率相当高,它界面简洁、标注任务配置灵活,支持文本分类、序列标注、序列到序列等常见任务,团队协作功能也算够用。但越多人用,就越要正视一个问题:很多团队把它部署好就丢在生产环境,默认配置跑到底,而它恰恰是攻击者眼里“高价值低防护”的靶子——上面不仅有标注数据,还有项目配置、用户账号、API 接口,一旦被打穿,轻则数据泄露,重则整个标注流水线瘫痪。

这篇指南不是安全理论课,而是基于我在真实项目里对 doccano 做安全加固的完整记录。围绕 SQL 注入与 XSS 这两类最常见的 Web 攻击,从原理拆解到 Django 层面的具体防护写法,再到数据库账号权限、Nginx 层兜底、部署后的自检清单,能直接抄作业。适合正在用或准备用 doccano 做标注平台的开发者、数据团队负责人,以及所有想把开源工具用得稍微体面一点的人。

1. 安全基线认知:doccano 的攻防面与纵深防御思路

1.1 两类攻击在标注平台上的真实风险

很多人觉得 SQL 注入和 XSS 是老生常谈,但在标注平台这种“多人协作 + 富文本内容 + 复杂查询”的场景里,它们的杀伤力会被明显放大。

先看 SQL 注入。doccano 的底层是 Django 框架,ORM 的默认参数化机制能挡住大部分低级拼接,但安全漏洞往往出在“绕过 ORM”的地方。项目里常见的高危点包括:编写自定义查询时直接使用connection.cursor()拼接条件;大量使用extra()或RawSQL处理标注结果统计;搜索功能里对用户输入做了奇怪的字符串处理后塞进filter()的参数;导入导出模块处理 JSON 或 CSV 时把字段名、表名参数化了——这种属于 Django 里最容易踩的坑,因为table_name这类标识符没法用占位符,一旦来自前端配置,就变成了注入点。

再看 XSS。标注平台天然是高危场景,因为大量用户输入的内容会被原样存进数据库,再被其他协作者、审核员或管理员在浏览器中查看。一个标注者粘贴了一段带有<script>标签的文本,或者一条注释里嵌入了事件属性,如果渲染时没有转义或过滤,这段脚本就会在另一个用户的浏览器里执行。攻击者可以利用这个通道窃取会话 Cookie、模拟管理员操作、读取标注界面下的敏感数据,甚至配合 CSRF 把项目配置改掉。比起传统网站的一次性攻击,标注平台里 XSS 的“潜伏期”更长——数据就静静躺在数据库里,谁打开谁中招。

1.2 纵深防御的设计逻辑

面对这两类风险,我的思路不是“只修代码”,而是把防线拆成三层:应用层挡输入、业务层管权限、基础设施层做兜底。

  • 应用层:规范所有数据库访问路径,强制走 ORM 参数化查询;对用户输入做白名单校验;模板渲染保持默认转义,对需要展示富文本的字段单独做白名单过滤。
  • 业务层:把权限模型收紧到“项目级 + 角色级”,限制普通标注者能触达的数据范围;对管理员操作增加二次校验;给所有用户加上登录限速和会话保护。
  • 基础设施层:数据库账号最小权限、Web 应用防火墙拦截常见攻击特征、Nginx 层配置安全响应头与请求体大小限制、定期审计日志。

这个逻辑对应到 doccano 上,还要考虑它本身的项目结构。doccano 是前后端分离的架构,后端是 Django REST Framework,前端是 Vue.js。前端通过 API 与后端交互,这意味着 XSS 面更大、API 接口更多,安全配置不能只看 Django 模板,还要覆盖 DRF 的认证机制、API 的访问控制,以及前端渲染时的转义行为。后面几个章节我会把每一层展开讲,并且给出可以直接用的配置片段。

2. SQL 注入防护全配置:从 ORM 到数据库权限的多层拦截

2.1 先把查询写对:ORM 参数化的正确姿势

doccano 的核心业务离不开对标注数据的检索、过滤和统计。最常见的安全隐患来自“想当然的过滤”和“图省事的原生 SQL”。我在做安全审计时,会先扫描整个项目里所有的objects.filter()、.exclude()、.annotate()以及所有包含raw()、extra()、connection.cursor()的地方。

先看一个反面教材,这种代码在一些二次开发过的 doccano 分支里真实存在:

from django.db import connection def search_projects(keyword): keyword = keyword.replace("'", "") sql = f"SELECT * FROM api_project WHERE name LIKE '%{keyword}%'" cursor = connection.cursor() cursor.execute(sql) return cursor.fetchall()

我见过有人用replace()去过滤单引号,以为这样就能防注入。实际上攻击者只需要用%和_做通配符攻击,或者利用注释符--打断后续语句,甚至直接传入完整的 UNION 查询。一次替换根本挡不住。

正确的姿势是彻底放弃这种拼接。Django ORM 自带参数化机制,占位符由框架帮你处理,你不需要手动转义:

from django.db.models import Q def search_projects(keyword): return Project.objects.filter(Q(name__icontains=keyword) | Q(description__icontains=keyword))

如果你确实需要执行原生 SQL,也必须用参数化游标:

from django.db import connection def search_projects(keyword): sql = """ SELECT * FROM api_project WHERE name LIKE %s OR description LIKE %s """ like_pattern = f"%{keyword}%" with connection.cursor() as cursor: cursor.execute(sql, [like_pattern, like_pattern]) return cursor.fetchall()

这里的关键点是%s占位符。无论用户输入什么,数据库驱动都会把它当作纯数据,而不是可执行的 SQL 代码。这是所有注入防护的地基,地基不牢,后面配置再多都是白搭。

2.2 动态查询、列表排序与统计接口的防护方案

doccano 的列表页通常支持按名称排序、按标签过滤、按标注状态筛选,这些动态条件如果处理不当,很容易把可控参数带进 SQL。我在实际审计中发现过这样一个模式:前端传?ordering=created_at,后端拿到后就拼进order_by():

ordering = request.GET.get("ordering", "-created_at") projects = Project.objects.all().order_by(ordering)

如果ordering参数来自前端且没有校验,攻击者传个id;DROP TABLE api_project--虽然不一定能直接执行,但配合异常报错能探测数据库结构;如果后端在排序前做了字符串拼接,则会产生真实的注入点。防护方法是建一个白名单映射:

ORDERING_WHITELIST = { "created_at": "created_at", "-created_at": "-created_at", "name": "name", "-name": "-name", "updated_at": "updated_at", } ordering = ORDERING_WHITELIST.get(request.GET.get("ordering", "-created_at"), "-created_at") projects = Project.objects.all().order_by(ordering)

同样的思路也适用于 filter 字段。doccano 里有很多查询参数是可选的,比如按project_type过滤、按annotation_status过滤,我建议统一走“参数名 → 模型字段”的映射函数,不存在的键直接忽略,而不是把前端传来的字符串直接当字段名用。

统计接口更要小心。标注平台经常要算“每个项目标注了多少条”“每个标注者完成了多少任务”,这类聚合查询如果用extra(select={...})或RawSQL拼接动态内容,风险极高。我一般建议把聚合逻辑完全固定下来:

from django.db.models import Count, Q stats = Project.objects.annotate( total_documents=Count("documents", distinct=True), completed_annotations=Count( "documents__annotations", filter=Q(documents__annotations__is_correct=True), distinct=True ), )

这种写法不涉及任何用户可控标识符,Django 会把整条 SQL 的参数化处理交给底层驱动,安全性和可读性都好得多。

2.3 数据库账号最小权限配置

即便应用层做了万无一失的参数化,也不能把数据库最高权限交给 Web 应用。这个教训我是在一次事故里学到的:某团队给 doccano 配的数据库账号直接用了 PostgreSQL 的超级用户,结果一次注入攻击把整个库的所有表都删了。后来我专门总结了一套最小权限策略:

项建议配置原因
连接账号专用账号,不共享便于审计和责任追踪
默认权限仅 SELECT / INSERT / UPDATE / DELETEdoccano 运行只需要这些基础操作
DDL 权限禁止 CREATE / DROP / ALTER防止攻击者通过注入创建恶意对象
超管权限仅运维使用,应用账号永不授权即使被注入也无法扩展攻击面

在 PostgreSQL 里,可以通过如下方式创建最小权限账号:

CREATE USER doccano_app WITH PASSWORD '随机强密码'; GRANT CONNECT ON DATABASE doccano TO doccano_app; GRANT USAGE ON SCHEMA public TO doccano_app; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO doccano_app; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO doccano_app; REVOKE CREATE ON SCHEMA public FROM doccano_app;

还有一个容易忽略的点:如果新表是在应用账号创建之后新增的,ALTER DEFAULT PRIVILEGES能解决未来表自动授权的问题。记住每次迁移数据库后检查一遍权限,别让迁移脚本把权限覆盖掉了。

2.4 敏感字段加密与脱敏

标注平台的数据价值高,但合规要求也高。doccano 默认把所有数据明文存库,一旦数据库泄露,所有标注内容、用户名、邮箱全部暴露。我的建议是至少做到两层:密码字段自动哈希(Django 默认已处理)和敏感业务字段的加密存储。

如果你在 doccano 上面接入了自定义的用户字段或私有备注内容,Django 侧可以用Fernet或django-cryptography这类库做字段级加密:

from django_cryptography.fields import encrypt class PrivateNote(models.Model): content = encrypt(models.TextField()) created_by = models.ForeignKey(User, on_delete=models.CASCADE)

这种方案能保证即使数据库文件被拖走,没有密钥的人也无法还原内容。密钥管理建议放到环境变量或独立的密钥服务里,不要写进代码仓库,更不能出现在 Docker Compose 的明文配置里。

2.5 用中间件与 WAF 做兜底

应用层代码写得再安全,也挡不住未来某个版本迭代引入新漏洞。我习惯在 Nginx 层加一道正则过滤,把明显的注入特征拦截在最外层:

location /api/ { if ($query_string ~* "(\bselect\b.*\bfrom\b|union\s+select|information_schema|benchmark\s*\()") { return 403; } proxy_pass http://doccano_backend; }

注意这种基于正则的过滤不能作为唯一防线,因为攻击者可以用编码绕过、注释拆分等手段绕过规则,但作为一层噪音拦截还是有效的,能显著减少扫描器的骚扰。

商用 WAF 或云平台的 Web 防火墙也是可用选项,我实测下来,对常见扫描流量的拦截率在 90% 以上。关键是配置好“严格模式”,同时开启日志记录,定期回看拦截记录,从中发现真实攻击手法。

3. XSS 防护全配置:从模板转义到 CSP 的策略组合

3.1 标注内容为什么是 XSS 重灾区

doccano 的工作流决定了它的 XSS 面很特殊:标注者可以往文本里插入任意内容,包括 URL、代码片段、HTML 标签、Emoji;审核员和项目管理员会查看这些内容并给出标注意见;平台开发者还会在管理后台里查看标注统计和导出内容。任何一个环节缺失转义,恶意脚本就能在别人的浏览器里跑起来。

更麻烦的是,doccano 的前端是 Vue.js 项目,默认的模板语法({{ }})确实会自动转义,但如果开发者为了让某段内容“看起来更好看”,用了v-html指令渲染用户提交的文本,转义就完全被跳过了。这种问题在自定义标注视图、预览面板、导出预览这类功能里很常见。

所以 XSS 防护要两头抓:后端存数据时不改原文(保留原始标注数据),渲染时按需转义或过滤;前端原则上禁止用v-html渲染任何用户可控内容,确实需要展示富文本时,先用白名单过滤库清洗一遍。

3.2 Django 模板自动转义的正确使用

Django 模板引擎默认开启自动转义,这是个好消息。但很多人在二次开发 doccano 时,会在模板里写|safe或者autoescape off,这才是翻车的开始。

自查一下你的模板里是否有这种写法:

<div> {{ annotation.text | safe }} </div>

这条代码等于告诉 Django:“我不需要转义,这段内容直接输出 HTML 吧。”如果文本来自用户输入,XSS 就在这里落地了。正确做法是去掉|safe,让默认转义生效:

<div> {{ annotation.text }} </div>

这样<script>alert(1)</script>会显示成纯文本,而不是被浏览器执行。

如果确实需要展示部分 HTML,比如标注工具要高亮某些关键词,我建议在后端用bleach库做白名单清洗,把允许的标签和属性明确列出来:

import bleach ALLOWED_TAGS = ["p", "br", "strong", "em", "a", "span", "mark", "b", "i"] ALLOWED_ATTRIBUTES = { "a": ["href", "title", "target"], "span": ["class", "data-*"], } ALLOWED_STYLES = ["color", "font-weight", "background-color"] cleaned_content = bleach.clean( raw_content, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRIBUTES, styles=ALLOWED_STYLES, strip=True, )

把这个清洗逻辑做成一个统一函数,在写入存储前和渲染输出前各执行一次,双保险。

3.3 CSP 策略配置实战

CSP(内容安全策略)是我在 doccano 防护里强烈建议加的一层,它能有效缓解即使转义失败也造成的危害。CSP 可以理解为告诉浏览器:哪些来源的脚本、样式、图片可以加载,其他的一律拦截。

在 Django 里加 CSP 响应头有两种方式:一个是手动在 Nginx 中配置,另一个是用django-csp中间件。我推荐用中间件方案,因为可以在不同视图里差异化设置。

安装并配置:

pip install django-csp
# settings.py MIDDLEWARE = [ # 放在最前 "csp.middleware.CSPMiddleware", ... ] CONTENT_SECURITY_POLICY = { "DIRECTIVES": { "default-src": ["'self'"], "script-src": ["'self'", "'unsafe-inline'"], "style-src": ["'self'", "'unsafe-inline'"], "img-src": ["'self'", "data:"], "connect-src": ["'self'"], "object-src": ["'none'"], "base-uri": ["'self'"], "frame-ancestors": ["'none'"], }, }

配置里有几个细节需要解释。'unsafe-inline'是为了兼容 doccano 前端里已有的内联脚本和样式,建议在完全审计后移除或收紧;frame-ancestors: 'none'能阻止页面被 iframe 嵌入,直接减少点击劫持攻击;object-src: 'none'则封堵了 Flash 等插件加载。

上线后我会用浏览器开发者工具看有没有被 CSP 拦截的资源,把确实可靠的域名加进白名单,其他的一律拦截。

3.4 上传文件的类型校验

doccano 不仅接收文本,还支持上传导入数据集文件。如果上传的是带有恶意脚本的 HTML 文件或 SVG 文件,当其他用户下载预览时,浏览器也会执行其中脚本。这类攻击属于Stored XSS的一种变体。

我的处理方案是:文件上传后先校验扩展名和 MIME 类型,然后强制重命名并改变存储路径:

ALLOWED_EXTENSIONS = {"txt", "csv", "json", "jsonl", "tsv"} ALLOWED_MIME_TYPES = { "text/plain", "text/csv", "application/json", "application/octet-stream", } def validate_upload(file_obj): ext = file_obj.name.split(".")[-1].lower() mime = file_obj.content_type if ext not in ALLOWED_EXTENSIONS or mime not in ALLOWED_MIME_TYPES: raise ValidationError("文件类型不允许")

另外,上传的标注文件里可能包含 HTML 片段或链接,在导出下载时也必须进行同样的转义处理。doccano 的导出功能如果直接拼接 CSV,同样是 XSS 传播的通道。

4. 认证授权与访问控制加固

4.1 密码策略与登录限速

doccano 默认使用 Django 的用户认证体系,密码校验强度取决于AUTH_PASSWORD_VALIDATORS配置。默认配置只限制了最小长度,我一般会改成带复杂度要求的组合:

AUTH_PASSWORD_VALIDATORS = [ {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", "OPTIONS": {"min_length": 12}}, {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"}, ]

密码要求只是第一步,真正要防的是暴力破解。我给 doccano 加了一个登录限速中间件,对同一个 IP 的登录失败次数做限制:

from django.core.cache import cache MAX_FAILED_ATTEMPTS = 5 LOCKOUT_SECONDS = 300 def check_login_lockout(ip): key = f"login_fail_{ip}" failed = cache.get(key, 0) if failed >= MAX_FAILED_ATTEMPTS: raise PermissionDenied("尝试次数过多,请稍后再试")

同时在 Nginx 层限制单 IP 的请求速率,双管齐下:

limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/m; location /v1/auth/login/ { limit_req zone=login_limit burst=10 nodelay; proxy_pass http://doccano_backend; }

4.2 双重验证与关键操作二次确认

对于管理员账号,我强烈建议开启双重验证。Django 生态里可以使用django-otp或django-two-factor-auth。虽然 doccano 本身没内置,但通过自定义认证后端可以很平滑地接入:

# settings.py AUTHENTICATION_BACKENDS = [ "django.contrib.auth.backends.ModelBackend", "django_otp.backends.OTPBackend", ]

启用后,管理员登录时除了用户名密码,还必须输入一次性验证码。这个机制能挡住绝大多数因密码泄露导致的越权访问。

另外,所有“删除项目”“清空标注数据”“修改用户角色”这类关键操作,我都加了二次确认弹窗,并在后端接口上要求传入confirm=true参数,防止用户误操作或 CSRF 攻击诱导操作。

4.3 角色与项目级权限梳理

doccano 的权限模型比较扁平:管理员、项目管理员、标注员、审核员。默认配置下,管理员能操作所有项目和数据。如果团队规模大,建议按“项目隔离”重新分配权限,让标注员只能看到分配给自己的任务。

这里的核心做法是用 DRF 的DjangoObjectPermissions配合guardian库做行级权限控制:

REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES": [ "rest_framework.permissions.DjangoObjectPermissions", ], }

并按角色设置 API 的白名单:

角色可访问接口说明
标注员获取文档、提交标注、查看个人任务禁止访问项目配置
审核员标注员全部权限 + 查看统计报表可以查看但无法修改
项目管理员项目内全部权限限制在项目范围内
平台管理员全部 API仅限平台配置与用户管理

权限收得越细,攻击者横向移动的空间就越小。即使一个标注员账号被攻破,最多影响他有权访问的那部分数据,其他项目的数据他碰不到。

5. 完整安全配置模板:一次可落地的部署参考

5.1 前置准备

开始配置前,先把 doccano 的 Docker Compose 部署方式和 Django 配置文件摸清楚。我的经验是:在容器部署模式下,把安全配置集中放在环境变量和独立配置文件中,避免直接改镜像内的代码文件,这样可以提高可维护性。

需要准备的内容:

  • 一份settings.py的追加配置片段
  • 一份 Nginx 安全配置
  • 一份 PostgreSQL 账号权限脚本
  • 一份部署后的自检清单

5.2 核心配置示例

下面是一份我实际用过的settings_secure.py追加配置,你可以直接复制到 doccano 项目的settings.py末尾:

# 安全增强配置 SECURE_CONTENT_TYPE_NOSNIFF = True SECURE_BROWSER_XSS_FILTER = True X_FRAME_OPTIONS = "DENY" CSRF_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True SESSION_COOKIE_HTTPONLY = True SECURE_SSL_REDIRECT = True # 限制请求体大小,防止超大请求冲击后端 DATA_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5MB FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5MB # DRF 认证与节流 REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.SessionAuthentication", "rest_framework.authentication.TokenAuthentication", ], "DEFAULT_THROTTLE_CLASSES": [ "rest_framework.throttling.AnonRateThrottle", "rest_framework.throttling.UserRateThrottle", ], "DEFAULT_THROTTLE_RATES": { "anon": "20/min", "user": "120/min", }, }

对应 Nginx 层配置:

server { listen 443 ssl http2; server_name your_domain; ssl_certificate /etc/nginx/certs/server.crt; ssl_certificate_key /etc/nginx/certs/server.key; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Content-Security-Policy "default-src 'self'; object-src 'none'; frame-ancestors 'none';" always; client_max_body_size 10m; location / { proxy_pass http://doccano_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

5.3 部署后的自检清单

配置完成后不能直接宣布“安全了”,我每次都会跑一遍自检清单:

  1. 用扫描器对公网地址做一次轻量扫描,确认没有检测到 SQL 注入或 XSS 特征。
  2. 在本地环境模拟注入 payload:' OR '1'='1、union select等,确认应用只返回空结果或 400,而不是数据库报错。
  3. 在标注内容里插入<script>alert(1)</script>,用审核员账号打开,确认脚本被转义为普通文本。
  4. 检查响应头是否包含X-Content-Type-Options: nosniff、X-Frame-Options: DENY等安全头。
  5. 确认数据库连接账号不是超级用户,且没有 DDL 权限。
  6. 确认登录接口连续失败 5 次后出现限流提示。
  7. 检查日志里是否有来自异常 IP 的扫描行为,有则通知运维封禁。

这套清单我也整理成了表格,方便每次上线或更新版本后逐项勾选:

检查项命令/方式预期结果
SQL 注入防护使用注入 payload 测试列表接口返回空结果或 400,无 SQL 报错
XSS 防护插入脚本标签后预览显示为纯文本
安全响应头curl -I查看响应头包含 nosniff、X-Frame-Options 等
数据库最小权限登录数据库执行CREATE TABLE权限不足报错
登录限速连续错误登录 6 次出现锁定提示
日志审计查看 nginx/application 日志无异常扫描记录

6. 常见问题排查与实战避坑

6.1 高频问题速查表

问题原因分析解决方案
页面能打开但 API 接口报 403安全头或 CSP 拦截了资源请求检查connect-src和frame-ancestors配置,放行合法资源
管理员登录后被强制退出SESSION_COOKIE_SECURE开启但未配置 HTTPS先完成 HTTPS 配置再开启此选项
标注文本里的 URL 无法正常点击模板默认转义导致链接没有href属性采用bleach白名单清洗后渲染,而不是盲加safe
导入 CSV 时部分行被过滤DATA_UPLOAD_MAX_MEMORY_SIZE限制了请求体大小按需调高,但不要超过 Nginx 的client_max_body_size
用户反馈登录变慢登录限速策略误伤正常玩家调整限速阈值并设置放行白名单 IP
数据库迁移失败最小权限账号缺少 DDL 权限迁移时用运维账号,迁移完切回应用账号

6.2 踩坑实录

这里记录一个让我印象深刻的坑:有一次我给 doccano 加了 CSP,结果前端图表全部变成空白,调试了很久才发现是img-src里漏掉了data:协议——图表库内部用 base64 生成了图片数据。这个案例说明,加安全头不能闭眼抄配置,必须结合项目实际运行情况做微调。

另一个坑是SECURE_SSL_REDIRECT。在容器内部署时,如果前端 Nginx 已经把 HTTP 转成了 HTTPS,后端实际上接收的是内部 HTTP 请求,再开SECURE_SSL_REDIRECT会导致无限重定向。解决办法是只在 Nginx 层做跳转,后端不开启这个选项,或者使用X-Forwarded-Proto头判断。

6.3 安全意识永远比配置本身重要

安全配置不是一次性工作。doccano 隔几个月就更新一次,每次更新都要重新检查一遍依赖版本,确认有没有新的 CVE 曝光。我个人的习惯是订阅相关的安全通告,每次发布新版本优先在测试环境跑一遍自检清单,再考虑是否升级生产环境。

如果团队没有专职安全人员,至少做到两条:一是永远不要用默认密码,二是永远不要把数据库端口直接暴露到公网。这两条能挡住一大半的低级攻击。

说实话,给 doccano 做安全加固这件事,投入产出比非常高。标注数据本身就是团队的核心资产,与其等出了事再补救,不如在部署初期就把这些配置写清楚。这篇指南里的每一行配置我都实际跑过,踩过的坑也写出来了,照着做不能说绝对安全,但至少能把攻击者的路堵掉九成。剩下的,交给持续关注和定期复查。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 12:08:36

空间机械臂双臂碰撞检测算法:几何求交、包围盒树与避碰策略

空间机械臂双臂碰撞检测算法&#xff0c;这个话题一看就是给在轨服务、空间装配这类任务做铺垫的。单臂操作时碰撞问题相对可控&#xff0c;一旦上双臂&#xff0c;两条臂协同抓取、拆装、对接&#xff0c;工作空间高度重叠&#xff0c;碰撞检测就不是“加一个判断函数”那么简…

作者头像 李华
网站建设 2026/10/22 12:08:28

Claude Code实时联网搜索:MCP协议实现语义化开发搜索

1. 项目概述&#xff1a;不是“联网”&#xff0c;而是让 Claude Code 真正理解“此刻的互联网” 最近在某跨平台AI开发实验室做模型能力边界测试时&#xff0c;反复遇到一个卡点&#xff1a;Claude Code&#xff08;指集成在Code IDE插件或本地开发环境中的Claude代码助手模块…

作者头像 李华
网站建设 2026/10/22 12:01:06

2026年Agent能力评测解析:分层基准与模型能力画像

1. 为什么“Agent 能力评测”突然变成了硬需求 先聊个现象。2026 年这个时间点&#xff0c;距离各类智能体&#xff08;Agent&#xff09;开始大规模进入生产环境&#xff0c;已经过去了好几年。市面上能跑通 Demo 的 Agent 项目多如牛毛&#xff0c;能稳定跑完一个业务流程的也…

作者头像 李华
网站建设 2026/10/22 12:00:47

从零手写.NET日志框架:核心设计与性能优化实践

1. 为什么我要自己动手写一个日志框架.NET 项目里几乎离不开日志。排查线上问题、跟踪用户请求链路、分析系统瓶颈&#xff0c;第一步都是翻日志。但很多开发者对日志的认知停留在“调一下 Log4Net 的配置”“用一下 ILogger 的扩展方法”&#xff0c;一旦出现日志丢失、时序错…

作者头像 李华