mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Speed up security filter middleware (#108703)
* Speed up security filter middleware Check the path and query string with the filter expression once instead of checking the path and query string seperately. If we get a hit than we check the query string to ensure we give a more verbose error about where the filter hit. Additionally since we see the same urls over and over, cache the unquote * request.url is to expensive, cheaper to join * aiohttp has a path_qs fast path * construct the string outselves so it functions exactly as before
This commit is contained in:
parent
617e8dd8a5
commit
9de8409f48
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
|
from functools import lru_cache
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from typing import Final
|
from typing import Final
|
||||||
@ -43,6 +44,7 @@ UNSAFE_URL_BYTES = ["\t", "\r", "\n"]
|
|||||||
def setup_security_filter(app: Application) -> None:
|
def setup_security_filter(app: Application) -> None:
|
||||||
"""Create security filter middleware for the app."""
|
"""Create security filter middleware for the app."""
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
def _recursive_unquote(value: str) -> str:
|
def _recursive_unquote(value: str) -> str:
|
||||||
"""Handle values that are encoded multiple times."""
|
"""Handle values that are encoded multiple times."""
|
||||||
if (unquoted := unquote(value)) != value:
|
if (unquoted := unquote(value)) != value:
|
||||||
@ -54,34 +56,38 @@ def setup_security_filter(app: Application) -> None:
|
|||||||
request: Request, handler: Callable[[Request], Awaitable[StreamResponse]]
|
request: Request, handler: Callable[[Request], Awaitable[StreamResponse]]
|
||||||
) -> StreamResponse:
|
) -> StreamResponse:
|
||||||
"""Process request and block commonly known exploit attempts."""
|
"""Process request and block commonly known exploit attempts."""
|
||||||
|
path_with_query_string = f"{request.path}?{request.query_string}"
|
||||||
|
|
||||||
for unsafe_byte in UNSAFE_URL_BYTES:
|
for unsafe_byte in UNSAFE_URL_BYTES:
|
||||||
if unsafe_byte in request.path:
|
if unsafe_byte in path_with_query_string:
|
||||||
|
if unsafe_byte in request.query_string:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Filtered a request with unsafe byte query string: %s",
|
||||||
|
request.raw_path,
|
||||||
|
)
|
||||||
|
raise HTTPBadRequest
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Filtered a request with an unsafe byte in path: %s",
|
"Filtered a request with an unsafe byte in path: %s",
|
||||||
request.raw_path,
|
request.raw_path,
|
||||||
)
|
)
|
||||||
raise HTTPBadRequest
|
raise HTTPBadRequest
|
||||||
|
|
||||||
if unsafe_byte in request.query_string:
|
if FILTERS.search(_recursive_unquote(path_with_query_string)):
|
||||||
|
# Check the full path with query string first, if its
|
||||||
|
# a hit, than check just the query string to give a more
|
||||||
|
# specific warning.
|
||||||
|
if FILTERS.search(_recursive_unquote(request.query_string)):
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Filtered a request with unsafe byte query string: %s",
|
"Filtered a request with a potential harmful query string: %s",
|
||||||
request.raw_path,
|
request.raw_path,
|
||||||
)
|
)
|
||||||
raise HTTPBadRequest
|
raise HTTPBadRequest
|
||||||
|
|
||||||
if FILTERS.search(_recursive_unquote(request.path)):
|
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Filtered a potential harmful request to: %s", request.raw_path
|
"Filtered a potential harmful request to: %s", request.raw_path
|
||||||
)
|
)
|
||||||
raise HTTPBadRequest
|
raise HTTPBadRequest
|
||||||
|
|
||||||
if FILTERS.search(_recursive_unquote(request.query_string)):
|
|
||||||
_LOGGER.warning(
|
|
||||||
"Filtered a request with a potential harmful query string: %s",
|
|
||||||
request.raw_path,
|
|
||||||
)
|
|
||||||
raise HTTPBadRequest
|
|
||||||
|
|
||||||
return await handler(request)
|
return await handler(request)
|
||||||
|
|
||||||
app.middlewares.append(security_filter_middleware)
|
app.middlewares.append(security_filter_middleware)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user