inveniosoftware / invenio-rdm-records

DataCite-based data model for InvenioRDM flavour.
https://invenio-rdm-records.readthedocs.io
MIT License
15 stars 87 forks source link

IIIF: handle DecompressionBombError #1766

Closed max-moser closed 2 months ago

max-moser commented 3 months ago

We sometimes get notifications about internal server errors from the IIIF endpoint, caused by an unhandled PIL.Image.DecompressionBombError: Image size (5179329012 pixels) exceeds limit of 178956970 pixels, could be decompression bomb DOS attack.

Exception on /iiif/record:zvvmh-nan78:first_flood_detection.tif/full/!800,800/0/default.jpg [GET]
Traceback (most recent call last):
  File "/usr/lib/python3.12/site-packages/flask/app.py", line 2529, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask/app.py", line 1825, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask/app.py", line 1823, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask_resources/resources.py", line 65, in view
    return view_meth()
           ^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask_resources/content_negotiation.py", line 116, in inner_content_negotiation
    return f(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask_cors/decorator.py", line 130, in wrapped_function
    resp = make_response(f(*args, **kwargs))
                         ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask_resources/parsers/decorators.py", line 51, in inner
    return f(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask_resources/parsers/decorators.py", line 51, in inner
    return f(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask_resources/parsers/decorators.py", line 51, in inner
    return f(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/invenio_rdm_records/resources/iiif.py", line 131, in _wrapper
    return f(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/invenio_rdm_records/resources/iiif.py", line 241, in image_api
    to_serve = self.service.image_api(
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/invenio_rdm_records/services/iiif/service.py", line 167, in image_api
    image = IIIFImageAPIWrapper.open_image(data)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/flask_iiif/api.py", line 581, in open_image
    image = Image.open(source)
            ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/PIL/Image.py", line 3482, in open
    im = _open_core(
         ^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/PIL/Image.py", line 3466, in _open_core
    _decompression_bomb_check(im.size)
  File "/usr/lib/python3.12/site-packages/PIL/Image.py", line 3365, in _decompression_bomb_check
    raise DecompressionBombError(msg)
PIL.Image.DecompressionBombError: Image size (5179329012 pixels) exceeds limit of 178956970 pixels, could be decompression bomb DOS attack.

I was unsure about which HTTP status code to use here and was almost leaning towards a 5XX, but in this StackOverflow question the code 403 was recommended (for valid reasons, IMO): https://stackoverflow.com/questions/15192477/http-status-code-when-single-request-asks-for-too-large-resource-or-too-many-of

max-moser commented 2 months ago

Update: This error gets triggered by the default previewer for TIFF images, e.g. on the landing page for: https://researchdata.tuwien.ac.at/records/zvvmh-nan78

Neither with nor without this PR does the previewer display anything meaningful for the TIFF image (both tested locally, with the TIFF file from the above record), but with this PR it's at least not a 500 response anymore.

image