手机照片契约与技术保护
| 保护项 | 值 | 检查阶段 |
|---|---|---|
| 每批数量 | 50张 | 前端及local_photos;试用额外10张累计 |
| 单图原始字节 | 20MiB | File读取预检/Base64解码与下载保护 |
| 批次原始字节 | 40MiB | 整批解码前累计验证 |
| 总像素 | 50,000,000 | 图片头/实际解码检查 |
| 单边 | 16384像素 | 图片尺寸验证 |
| 请求体 | 64MiB | Flask MAX_CONTENT_LENGTH |
上传以JSON Base64字符串传入:前端先从FileReader的Data URL结果剥除data:image/...;base64,前缀,后端只接受严格Base64,不会自动替API调用者剥除此前缀。不能只因扩展名就把任意数据当成图片。图片解码先校正EXIF方向、取第一帧、透明图铺白底、转换RGB并重编码PNG,删除原始元数据。整批先验证,某张失败提示对应位置,不部分保存并替换已有任务。
常见JPEG/PNG/WebP/GIF/BMP/TIFF由Pillow读取。遇到ISO BMFF的ftyp类数据且Pillow失败时,Android路径尝试系统ImageDecoder,再把Bitmap压成PNG重新规范化,检查像素并recycle。ImageDecoder是API28能力,minSdk24设备未必具有该类或相应格式解码,异常会给出读取失败;APK没有强制打包pillow-heif解码器。
输入大小限制是压缩原始字节,不限制转换后所有PNG总大小或精确解码峰值。规范化源图保留像素,直到cover阶段才缩成1080p;高像素PNG、许多照片和长任务仍可能增加内存/空间压力。
公网URL校验与连接
URL必须http/https、host非空、无user/password、无空白控制字符,长度最多8192,端口仅80或443,拒绝host中的zone编码。DNS结果中的每个IP都需公网global且非multicast/reserved,拒绝私网、回环、IPv4映射绕过、6to4、Teredo和NAT64特殊前缀;全部安全后优先IPv4。
下载将连接绑定到已验证IP;HTTPS仍以原域名做SNI和证书校验,减少DNS重绑定风险。每次跳转重新验证,最多4次请求即最多3个有效跳转,拒绝HTTPS降级HTTP。socket等待20秒不等于整个下载总时长保证20秒;代码没有另一个全过程总计时器。
响应要求200、非明显HTML,大小最多20MiB。请求不携带用户Cookie、云Key或账号,Accept-Encoding=identity;兼容gzip/deflate时还限制解压大小,拒绝异常或未支持编码。下载结束仅保存规范化图片与最终来源域名元数据,不持久保存完整URL。
网址任务的URL只在Control内存中,处理finally清空;重启后的失败网址任务无法从job恢复原直链,需要用户重新提供。图片直链能力不含文章解析、登录绕过、网页多图提取或后台爬取。
依据:photo_import.py:17–192、android_runtime.py:272–289、app.py:198–209。