1
0
mirror of https://gitlab.com/fdroid/fdroidserver.git synced 2024-11-14 11:00:10 +01:00

update: strip EXIF data from all JPEGs

EXIF data can be abused to exploit systems a lot easier than the JPEG image
data can.  The F-Droid ecosystem does not use the EXIF data, so keep things
safe and strip it all away.  There is a chance that some images might rely
on the rotation to be set by EXIF, but I think having a safe system is more
important.

If needed, only the rotation data could be saved.  But that then makes it
hard to tell which images have been stripped.  This way, if there is no
EXIF, it has been stripped.  And if there is EXIF data, then it is suspect.

https://securityaffairs.co/wordpress/51043/mobile-2/android-cve-2016-3862-flaw.html
https://threatpost.com/google-shuts-down-potentially-massive-android-bug/120393/
https://blog.sucuri.net/2013/07/malware-hidden-inside-jpg-exif-headers.html

The big downside of this is that it decompresses and recompresses the
image data.  That should be replaced by a technique from jhead,
exiftool, ObscuraCam, etc. that only strips the metadata.
This commit is contained in:
Hans-Christoph Steiner 2017-12-13 11:57:36 +01:00
parent bde0558d82
commit 67b9514c5a

View File

@ -672,6 +672,27 @@ def _set_author_entry(app, key, f):
app[key] = text
def _strip_and_copy_image(inpath, outpath):
"""Remove any metadata from image and copy it to new path
Sadly, image metadata like EXIF can be used to exploit devices.
It is not used at all in the F-Droid ecosystem, so its much safer
just to remove it entirely. PNG does not have the same kind of
issues.
"""
if common.has_extension(inpath, 'png'):
shutil.copy(inpath, outpath)
else:
with open(inpath) as fp:
in_image = Image.open(fp)
data = list(in_image.getdata())
out_image = Image.new(in_image.mode, in_image.size)
out_image.putdata(data)
out_image.save(outpath, "JPEG", optimize=True)
def copy_triple_t_store_metadata(apps):
"""Include store metadata from the app's source repo
@ -744,7 +765,7 @@ def copy_triple_t_store_metadata(apps):
sourcefile = os.path.join(root, f)
destfile = os.path.join(destdir, os.path.basename(f))
logging.debug('copying ' + sourcefile + ' ' + destfile)
shutil.copy(sourcefile, destfile)
_strip_and_copy_image(sourcefile, destfile)
def insert_localized_app_metadata(apps):
@ -842,7 +863,7 @@ def insert_localized_app_metadata(apps):
if base in GRAPHIC_NAMES and extension in ALLOWED_EXTENSIONS:
os.makedirs(destdir, mode=0o755, exist_ok=True)
logging.debug('copying ' + os.path.join(root, f) + ' ' + destdir)
shutil.copy(os.path.join(root, f), destdir)
_strip_and_copy_image(os.path.join(root, f), destdir)
for d in dirs:
if d in SCREENSHOT_DIRS:
if locale == 'images':
@ -854,7 +875,7 @@ def insert_localized_app_metadata(apps):
screenshotdestdir = os.path.join(destdir, d)
os.makedirs(screenshotdestdir, mode=0o755, exist_ok=True)
logging.debug('copying ' + f + ' ' + screenshotdestdir)
shutil.copy(f, screenshotdestdir)
_strip_and_copy_image(f, screenshotdestdir)
repofiles = sorted(glob.glob(os.path.join('repo', '[A-Za-z]*', '[a-z][a-z][A-Z-.@]*')))
for d in repofiles: