文章 569
评论 5
浏览 217477
图片上传 EXIF 信息泄露隐私:GPS 坐标自动剥离?Metadata 提取+ImageIO 自动旋转

图片上传 EXIF 信息泄露隐私:GPS 坐标自动剥离?Metadata 提取+ImageIO 自动旋转

在社交 App中,用户上传的照片被发现带有 GPS 坐标。一名用户通过下载其他用户的照片、提取 EXIF 信息,精确定位到了对方的家庭住址。事情闹大后,安全团队紧急处理——所有已上传的照片都没做 EXIF 处理,相机拍出来的每一张照片都带着 GPS 经纬度、设备型号、拍摄时间。

用户上传一张照片,本以为分享的是美景,实际上暴露了坐标、手机型号、拍摄参数。今天聊聊怎么在上传环节自动剥离 EXIF 信息,同时处理好照片的旋转问题。


EXIF 里藏着什么

一张 iPhone 拍的照片,EXIF 里可能包含:

  • GPS 经纬度(GPSLatitude / GPSLongitude)—— 精确到米
  • 设备信息(Make / Model)—— "iPhone 15 Pro"
  • 拍摄时间(DateTimeOriginal)
  • 旋转方向(Orientation)—— 手机横拍还是竖拍

前三个是隐私问题。最后一个是显示问题——手机竖着拍的照片,在电脑上可能横着显示,因为 Orientation 标记了旋转角度,但不是所有看图软件都会正确解析。


剥离 EXIF:转码后重新输出

最简单的方法:把图片用 ImageIO 读进来,再写出去。这个过程中 EXIF 信息会自动丢失:

public byte[] stripExif(byte[] imageBytes) throws IOException {
    BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageBytes));
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ImageIO.write(image, "jpg", out);
    return out.toByteArray();
}

原理是 ImageIO.write 会重新编码图片,重新编码时不会保留原始 EXIF。代价是图片被重新压缩了一次——如果原图是高质量 JPEG,重新编码可能损失画质。

不想损失画质的方案是用第三方库(如 Apache Commons Imaging 或 metadata-extractor)直接读写 EXIF 段,只删除敏感字段,不动图片数据本身。


自动旋转:根据 Orientation 纠正方向

手机竖拍的照片,EXIF Orientation 可能标记为 6(顺时针 90 度)或 8(逆时针 90 度)。剥离 EXIF 之后,后续如果新的图片查看器不知道方向信息,照片的方向会变成竖向存储,显示不出来正确方向——所以剥离前先按 Orientation 旋转:

public BufferedImage autoRotate(BufferedImage image, int orientation) {
    return switch (orientation) {
        case 6 -> rotate(image, 90);   // 顺时针 90°
        case 3 -> rotate(image, 180);  // 旋转 180°
        case 8 -> rotate(image, 270);  // 逆时针 90°
        default -> image;              // 1 = 正常,不需要旋转
    };
}

private BufferedImage rotate(BufferedImage src, int degrees) {
    int w = src.getWidth(), h = src.getHeight();
    int newW = (degrees == 90 || degrees == 270) ? h : w;
    int newH = (degrees == 90 || degrees == 270) ? w : h;

    BufferedImage dest = new BufferedImage(newW, newH, src.getType());
    Graphics2D g = dest.createGraphics();
    g.translate((newW - w) / 2.0, (newH - h) / 2.0);
    g.rotate(Math.toRadians(degrees), w / 2.0, h / 2.0);
    g.drawImage(src, 0, 0, null);
    g.dispose();
    return dest;
}

旋转完后再剥离 EXIF,图片方向就"固化"到了像素里——换任何看图软件打开都是正确的方向。


完整的处理流程

用户上传图片
  ├─ 1. 提取 EXIF Metadata
  │    ├─ GPS 坐标 → 记录日志(可选,用于审计)
  │    ├─ Orientation → 决定是否旋转
  │    └─ 其他字段 → 后续要清理
  │
  ├─ 2. 根据 Orientation 旋转图片(固化方向)
  │
  └─ 3. 剥离 EXIF(输出干净图片)
       └─ 存储到 OSS / 本地

用到 metadata-extractor 提取 EXIF:

Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(bytes));
ExifIFD0Directory exif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);

// 提取 Orientation
int orientation = exif != null ? exif.getInt(ExifIFD0Directory.TAG_ORIENTATION) : 1;

// 提取 GPS(记录日志后删掉)
GpsDirectory gps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
if (gps != null && gps.getGeoLocation() != null) {
    log.info("图片包含 GPS: {}, 已剥离", gps.getGeoLocation());
}

需要注意的点

缩略图也有 EXIF。JPEG 文件里可能包含一个嵌入的缩略图,缩略图也有独立的 EXIF 数据。用 metadata-extractor 可以检测并清理。

PNG 也有元数据。PNG 的元数据不在 EXIF 段,而在 tEXt / iTXt / zTXt 块里。不过 GPS 信息通常不会出现在 PNG 里(手机拍的照片是 JPEG),所以这个风险较低。

画质损失可控。重新编码 JPEG 会损失画质,但如果质量设为 0.92~0.95,肉眼几乎看不出差异。如果追求无损,用 Apache Commons Imaging 直接操作 EXIF 段。


总结

图片上传 EXIF 泄露的三件事:

  • 提取 Metadata —— metadata-extractor 读取 GPS、Orientation、设备信息
  • 自动旋转 —— 根据 Orientation 旋转图片,方向固化进像素
  • 剥离 EXIF —— 重新编码输出,敏感信息全部消失

用户上传一张照片,后端自动做这三步,返回一张方位正确、隐私干净的图片。成本和风险都很低,但能避免一次严重的隐私泄露事故。



标题:图片上传 EXIF 信息泄露隐私:GPS 坐标自动剥离?Metadata 提取+ImageIO 自动旋转
作者:jiangyi
地址:http://jiangyi.space/articles/2026/07/07/1783149825891.html
公众号:服务端技术精选

服务端开发博客:后端架构、高并发、性能优化与微服务实战教程

取消