diff --git a/apiserver/main.py b/apiserver/main.py index fcfbeb61dd71aeeab871f2c0ce0342cd4ddfc36e..f527e4bde179be09e1305b4bc32dfaa5185df388 100644 --- a/apiserver/main.py +++ b/apiserver/main.py @@ -15,7 +15,7 @@ from .config import ApiserverSettings from .security import (ACCESS_TOKEN_EXPIRES_MINUTES, JsonDBInterface, Token, User, authenticate_user, create_access_token, get_current_user) -from .storage import JsonFileStorageAdapter, LocationData, LocationDataType +from .storage import JsonFileStorageAdapter, LocationData, LocationDataType, verify_oid class ReservedPaths(str, Enum): @@ -86,6 +86,8 @@ async def list_datasets(location_data_type: LocationDataType): @app.get("/{location_data_type}/{dataset_id}", response_model=LocationData) async def get_specific_dataset(location_data_type: LocationDataType, dataset_id: str): """returns all information about a specific dataset, identified by id""" + if not verify_oid(dataset_id): + raise HTTPException(status_code=400, detail="Invalid OID format!") return adapter.get_details(location_data_type, dataset_id) @app.post("/{location_data_type}") @@ -101,6 +103,8 @@ async def update_specific_dataset(location_data_type: LocationDataType, dataset_id: str, dataset: LocationData, user: User = Depends(my_user)): """update the information about a specific dataset, identified by id""" + if not verify_oid(dataset_id): + raise HTTPException(status_code=400, detail="Invalid OID format!") return adapter.update_details(location_data_type, dataset_id, dataset, user.username) @@ -109,6 +113,8 @@ async def delete_specific_dataset(location_data_type: LocationDataType, dataset_id: str, user: str = Depends(my_user)): """delete a specific dataset""" + if not verify_oid(dataset_id): + raise HTTPException(status_code=400, detail="Invalid OID format!") # TODO: 404 is the right answer? 204 could also be the right one return adapter.delete(location_data_type, dataset_id, user.username) diff --git a/apiserver/storage/JsonFileStorageAdapter.py b/apiserver/storage/JsonFileStorageAdapter.py index 45106946ada5fc1274e11d5dd05a582ebdddaada..b2197a2d1011fed08ec701f294e76deebc827967 100644 --- a/apiserver/storage/JsonFileStorageAdapter.py +++ b/apiserver/storage/JsonFileStorageAdapter.py @@ -24,6 +24,17 @@ def get_unique_id(path: str) -> str: oid = str(uuid.uuid4()) return oid + +def verify_oid(oid: str, version=4): + """ Ensure thatthe oid is formatted as a valid oid (i.e. UUID v4). + If it isn't, the corresponding request could theoretically be an attempted path traversal attack (or a regular typo). + """ + try: + uuid_obj = uuid.UUID(oid, version=version) + except: + return False + return str(uuid_obj) == oid + class JsonFileStorageAdapter(AbstractLocationDataStorageAdapter): """ This stores LocationData via the StoredData Object as json files diff --git a/apiserver/storage/__init__.py b/apiserver/storage/__init__.py index 3d63565e7b7cc56a1939e1b1371edffbfdfd95e9..8c48a896dd34600a875076a9603eeb6f52574e5c 100644 --- a/apiserver/storage/__init__.py +++ b/apiserver/storage/__init__.py @@ -1,3 +1,3 @@ -from .JsonFileStorageAdapter import JsonFileStorageAdapter +from .JsonFileStorageAdapter import JsonFileStorageAdapter, verify_oid from .LocationStorage import LocationDataType, LocationData, AbstractLocationDataStorageAdapter \ No newline at end of file