607 # Api call to read data for northumbria
608 with urllib.request.urlopen(northumbriaUrl_04_2021) as resp1:
609 northumbria2021Data = resp1.read()
610 with urllib.request.urlopen(northumbriaUrl_04_2020) as resp2:611 northumbria2020Data = resp2.read()
612 # Api call to read data for cleveland
613
605 northumbriaUrl_04_2021 = getUrl("northumbria", "2021-03")
606 northumbriaUrl_04_2020 = getUrl("northumbria", "2020-04")
607 # Api call to read data for northumbria
608 with urllib.request.urlopen(northumbriaUrl_04_2021) as resp1:609 northumbria2021Data = resp1.read()
610 with urllib.request.urlopen(northumbriaUrl_04_2020) as resp2:
611 northumbria2020Data = resp2.read()
552 # Api call to read data for northumbria
553 with urllib.request.urlopen(northumbriaUrl_04_2021) as resp1:
554 northumbria2021Data = resp1.read()
555 with urllib.request.urlopen(northumbriaUrl_04_2020) as resp2:556 northumbria2020Data = resp2.read()
557 # Api call to read data for cleveland
558
550 # clevelandUrl_07_2021 = getUrl("cleveland", "2021-07")
551 # clevelandUrl_08_2021 = getUrl("cleveland", "2021-08")
552 # Api call to read data for northumbria
553 with urllib.request.urlopen(northumbriaUrl_04_2021) as resp1:554 northumbria2021Data = resp1.read()
555 with urllib.request.urlopen(northumbriaUrl_04_2020) as resp2:
556 northumbria2020Data = resp2.read()
466 clevelandJuneData = resp4.read()
467 with urllib.request.urlopen(clevelandUrl_07_2021) as resp5:
468 clevelandJulyData = resp5.read()
469 with urllib.request.urlopen(clevelandUrl_08_2021) as resp6:470 clevelandAugustData = resp6.read()
471 # Read and load data in panada dataframe
472 json_format_cleveland_june = json.loads(clevelandJuneData)
464 # Api call to read data for cleveland
465 with urllib.request.urlopen(clevelandUrl_06_2021) as resp4:
466 clevelandJuneData = resp4.read()
467 with urllib.request.urlopen(clevelandUrl_07_2021) as resp5:468 clevelandJulyData = resp5.read()
469 with urllib.request.urlopen(clevelandUrl_08_2021) as resp6:
470 clevelandAugustData = resp6.read()
462 with urllib.request.urlopen(northumbriaUrl_08_2021) as resp3:
463 northumbriaAugustData = resp3.read()
464 # Api call to read data for cleveland
465 with urllib.request.urlopen(clevelandUrl_06_2021) as resp4:466 clevelandJuneData = resp4.read()
467 with urllib.request.urlopen(clevelandUrl_07_2021) as resp5:
468 clevelandJulyData = resp5.read()
459 northumbriaJuneData = resp1.read()
460 with urllib.request.urlopen(northumbriaUrl_07_2021) as resp2:
461 northumbriaJulyData = resp2.read()
462 with urllib.request.urlopen(northumbriaUrl_08_2021) as resp3:463 northumbriaAugustData = resp3.read()
464 # Api call to read data for cleveland
465 with urllib.request.urlopen(clevelandUrl_06_2021) as resp4:
457 # Api call to read data for northumbria
458 with urllib.request.urlopen(northumbriaUrl_06_2021) as resp1:
459 northumbriaJuneData = resp1.read()
460 with urllib.request.urlopen(northumbriaUrl_07_2021) as resp2:461 northumbriaJulyData = resp2.read()
462 with urllib.request.urlopen(northumbriaUrl_08_2021) as resp3:
463 northumbriaAugustData = resp3.read()
455 clevelandUrl_07_2021 = getUrl("cleveland", "2021-07")
456 clevelandUrl_08_2021 = getUrl("cleveland", "2021-08")
457 # Api call to read data for northumbria
458 with urllib.request.urlopen(northumbriaUrl_06_2021) as resp1:459 northumbriaJuneData = resp1.read()
460 with urllib.request.urlopen(northumbriaUrl_07_2021) as resp2:
461 northumbriaJulyData = resp2.read()
410 )
411 with urllib.request.urlopen(clevelandUrl) as resp1:
412 clevelandData = resp1.read()
413 with urllib.request.urlopen(northumbriaUrl) as resp2:414 northumbriaData = resp2.read()
415 # Read and load data in panada dataframe
416 jsonFormatCleveland = json.loads(clevelandData)
408 clevelandUrl = (
409 "https://data.police.uk/api/stops-force?force=cleveland&date=2021-06"
410 )
411 with urllib.request.urlopen(clevelandUrl) as resp1:412 clevelandData = resp1.read()
413 with urllib.request.urlopen(northumbriaUrl) as resp2:
414 northumbriaData = resp2.read()
urllib
not only opens http://
or https://
URLs, but also ftp://
and file://
.
With this, it might be possible to open local files on the executing machine which might be a security risk if the URL to open can be manipulated by an external user.
The urllib.request
module defines functions and classes which help in opening URLs. urllib.request.open
can open ftp://
and file://
URLs. This is usually not intended and makes the application vulnerable to Server Side Request Forgery attack.
Performing requests from user-provided data could allow attackers to make requests on the internal network or change, retrieve or delete sensitive information. You are yourself responsible for validating the URL before opening it with urllib
.
It is recommended to validate the user-provided data, such as the URL and headers used to construct the request.
Since this is an audit issue, some occurrences may be harmless here. The goal is to bring the issue in attention. Please make sure that the url is trusted. If the occurrences doesn't seem to be valid, please feel free to ignore them.
Bad practice
req = urllib.Request.request(url)
resp = urllib.request.urlopen(req)
Recommended
# Validate URL before opening it
if url.lower().startswith('http'):
req = urllib.Request.request(url)
else:
raise ValueError from None
with urllib.request.urlopen(req) as resp:
[...]
## References:
- OWASP Top 10 2021 Category A10 - [Server Side Request Forgery](https://owasp.org/Top10/A10_2021-Server-Side_Request_Forgery_%28SSRF%29/)
- [CWE-918](https://cwe.mitre.org/data/definitions/918.html) - Server-Side Request Forgery (SSRF)