6 ms·
Htmx does not play well with content security policy
- foreigner 2y agoAlpine.js has the same problem, but it's just so darn useful
- deleted 2y ago[deleted]
- hshsh667 2y agoI wonder how the HTMX creator will respond, seems valid
- Ayesh 2y agohttps://htmx.org/essays/htmx-sucks/#xss-vulnerabilities https://htmx.org/essays/htmx-sucks/#xss-vulnerabilities
- zarzavat 2y agoOkay this whole article is hilarious. I still don’t want to use HTMX but now I will happily not use it, rather than angrily not use it like I do with golang.
- Quothling 2y agoYou should try HTMX and Golang together, it's an amazingly productive way to build internal tools. Our JS framework of choice is react, but the time it takes to configure a new project in our mono-repo I could've build the whole tool with HTMX and Go. This isn't to shit on react (or our setup) they are both excellent, it's simply to highlight just how productive you can be with those tools. It's a "use responsible" sort of tech stack though, but for a lot of things... well... it's fine. We're talking about a world where the alternative might be giving some team excel access directly to a production DB. Which is infinitely stupid x 2, but it still happens if development moves too slow.
- zarzavat 2y agoIt’s just not for me. HTMX fits into the middle ground: websites that are too dynamic to be made with a SSG or CMS, but not dynamic enough to be a SPA. I don’t work on enough things that fit into that category to justify learning an entire new framework. I’d rather just write React or even use plain JS. HTMX obviously can’t be used to build a SPA, so even if it were incredible I would still have to keep my React skills up. I’d also worry that if I build something in HTMX and it increases in scope, I’d end up rewriting it in React or maintaining a bird’s nest. It’s easy for me to tell the difference between webthings that “need to be SSG’d” and “needs React”, if I insert HTMX in the middle then I’d be second guessing if I made the right choice. As for Golang, again I’m just not the target market for it. It took them so long to decide to add generics. For me generics are a basic feature not a nice to have. I don’t agree with the goals of the language, so there’s no point in me learning it.
- zer00eyz 2y agoI moved from PHP to GO I brought the hate with me. In all honestly you're allowed to not like a thing (or golfing). You carry on doing you and leave the go jobs to me ;)
- Quothling 2y agohttps://htmx.org/docs/#security https://htmx.org/docs/#security
- Ayesh 2y agoHTMX always assumes that the incoming HTML is properly sanitized. If it isn't, the application is already vulnerable. HTMX triggers do in fact use JavaScript eval(), which will get blocked with a CSP that does not allow it. But you can use standard JS scripts to add events. The same goes for inline CSS.
- victorbjorklund 2y agoNot really news. Always sanitize user input html. No matter if you use HTMX or something else.
- dkdbejwi383 2y agoSure, but you should always not trust any input, even if you think it's been sanitized.
- mtlynch 2y agoThe relevant thing here is that before, CSP would protect you even if you failed to sanitize an attacker-controlled input. Bringing in htmx allows the attacker to bypass CSP, and that hasn't been documented well before. The htmx docs mention CSP in passing but don't explore the nuance that OP does.
- wccrawford 2y agoI think that's only true if your CSP has the word 'unsafe' or '*' in it. If it doesn't, it shouldn't allow inline code or things from domains that you didn't whitelist. And that's not HTMX or CSP's fault.
- mtlynch 2y ago>I think that's only true if your CSP has the word 'unsafe' or '*' in it. No, that's the subtlety that a lot of people in the thread are missing. I wish OP did a better job of explaining the difference. Imagine that you screw up and some part of your page assigns injects an attacker-controlled string without encoding properly: So you have something like this: <div class="ugc">{{ user_message }}</div> And the attacker can inject arbitrary HTML/JS, so they do this: <div class="ugc"><script>fetch('/account', { method: 'DELETE' })</script></div> If you have CSP enabled with standard settings, the attack won't execute. CSP saves you even if you screwed up that badly. The problem is that even if you keep the CSP settings secure and you add htmx into your app, the attacker can effectively achieve XSS because htmx's functionality is powerful enough that it's mostly equivalent to having arbitrary JS execution: <div class="ugc"><span hx-delete="/account" hx-trigger="load"></span></div> So, without htmx, CSP protects you from mistakenly sanitizing input / encoding output, but with htmx, you lose a lot of the benefit of CSP.
- CGamesPlay 2y agoSo, CSP is designed to help against the case where an XSS already happened. So, a lot of this seems like valid criticism, but some parts seem wrong. The "loading malicious fragments" part looks more like the motivating case for using CSP in the first place, rather than an implication of HTMX, but correct me if I'm wrong. The "unsafe eval" and "nonces for inline scripts" sections seem like valid criticisms of how HTMX works currently. It seems both are possible to disable using the configuration, though (meaning you could remove unsafe-eval from your CSP and htmx would still work except the disabled features). The "hx-disable" one seems like a badly designed security feature, frankly. BUT, the code that rendered the unsanitized HTML content was not htmx (looked like an erb template), so htmx shouldn't really be blamed for that one.
- iamkonstantin 2y agoit’s unclear what point the post is trying to make. The outlined behaviour is not specific to HTMx per-se. These are security considerations for all server rendered pages. The “basic” golden rules: - Only call routes you control - Always use an auto-escaping template engine - Only serve user-generated content inside HTML tags - If you have authentication cookies, set them with Secure, HttpOnly, and SameSite=Lax https://htmx.org/essays/web-security-basics-with-htmx/ https://htmx.org/essays/web-security-basics-with-htmx/
- andybak 2y ago> These are security considerations for all server rendered pages Well - "server rendered" to my ears primarily means plain html generated on the server using Perl, Python, PHP, CGI or whatever. I presume you mean "server rendered with some client-side code to handle injecting into the current DOM. Am I just too old-school or does using "server rendered" to mean fairly specific things seem strange?
- isodev 2y agoYou're correct. Server-rendered pages may also have some client-side interactivity using, for example, JavaScript/AJAX.... It doesn't need to be a fancy framework like htmx, but one needs to be mindful about user input and remote content either way. The same "techniques" for securing a web page remain in effect.
- vidarh 2y agoIt doesn't matter how it's rendered or where it's rendered. If it lets user A put unescaped/filtered/sanitised data on user B's pages, it's a security issue, no matter how the page was rendered. It's one that can be mitigated in various ways, but it's important to take into account.
- deleted 2y ago[deleted]
- the8472 2y agoThe point of CSP is to lock down your site so that any content (buggy or malicious) can't do damage. This requires templating engines to separate styles, scripts and event handlers from the html. > These are security considerations for all server rendered pages. That's not true. With the right CSP and sandbox rules content can be made inert without sanitizing. Sanitizing is still a good idea of course, but a rendering engine that is designed with CSP in mind will provide more layers of defense.
- ackers 2y agoI don't see the point of this article, it's just common sense. If you plan which parts of the DOM are replaced using HTMX, never trust user input. You'll be fine. I use Golang with HTMX and it's amazingly productive.
- ramon156 2y agoNot everyone's as knowledged, hence information should be shared
- qsort 2y agoI think the point is that htmx is in no way special. It's the same old category of vulnerability. It's why we have execvpe. It's why we have mysql_real_escape_string_no_really_we_mean_it_this_time(). I remember a similar point being made about LLM output. Now, I'm anything but a LLM fanboy, but if you pipe unknown text into a system interface that's squarely on you.
- yawaramin 2y agoAnd fortunately, it was https://htmx.org/essays/web-security-basics-with-htmx/ https://htmx.org/essays/web-security-basics-with-htmx/
- esjeon 2y agoI mean that's the point. Reminding people of possible dangers is one very important security mission.
- pessimizer 2y agoI think the point being made that you're replying to is that it has nothing to do with htmx. It isn't htmx that's not playing well with content security policy.
- yencabulator 2y agoUsing htmx effectively prevents using CSP for security hardening.
- theandrewbailey 2y agoI was under the impression that most (if not all) browser JS frameworks need hilariously bad CSPs like this, particularly for dynamic styling. Am I mistaken? I'm surprised that CSPs with unsafe-inline aren't treated with the same hate that table based layouts get. They are really bad.
- stouset 2y agoIf you allow random users to write arbitrary unsanitized HTML into other users’ pages, you have already lost, htmx or otherwise.
- bakugo 2y ago> If you allow random users to write arbitrary unsanitized HTML into other users’ pages, you have already lost Not really. The whole point of CSP is that, even if someone manages to inject arbitrary HTML into your page due to a bug or oversight, you can prevent injected scripts from running entirely, severely limiting what an attacker can do. I'm surprised at the amount of comments on this post that seem to be completely clueless about CSP.
- elmigranto 2y ago> if someone manages to inject arbitrary HTML If they can, why wouldn’t it be inline <script>?
- Akronymus 2y agoserving html with string concatenation is just like creating sql statements with string concat. At least thats how I see it. Ideally you'd use something similar to prepared statements, just for html templates.
- stouset 2y agoCSP is a backstop that—when configured properly and used alongside restraint in how you script—can minimize some of the worst consequences of injection. It doesn’t wash your hands clean of the responsibility to restrict what kinds of content users can inject into served pages.
- mtlynch 2y agoThere are some good points here, but I think the author neglects to dig deeper and explain how you can mitigate some of these risks with htmx settings. I've been using htmx with CSP for the past couple of weeks, and I do find that it expands attack surface in an unpleasant way, but I do still think it brings enough value that I'm willing to rely on other protections. >That cors.php file contains the JavaScript payload, and also sets CORS headers so that the browser has access to it. The following htmx settings should defeat this: htmx.config.selfRequestsOnly = true; htmx.config.allowScriptTags = false; htmx.config.allowEval = false; >HTMX has functionality that automatically adds the correct nonce to inline scripts it retrieves. This is convenient, but totally breaks the security model of CSP with nonces. Agreed, this seems like an anti-feature that completely subverts CSP. >Of course, this is trivial to bypass: just close the div tag with </div> and insert your payload outside of the element with the hx-disable attribute. This is true, but it kind of glosses over the fact that you have to screw up a lot more to give the attacker complete control over the HTML. Usually you're not just executing attacker-controlled content as HTML. If you're using a templating system, the more likely vulnerability is that the attacker is limited to escaping an HTML attribute and adding extra one. That said, it's true that if you have a vulnerability that allows an attacker can escape one context, it's much more likely that they can escape them all. >For these to work, the application has to allow evaluating dynamic code, using the CSP option unsafe-eval. However, allowing unsafe-eval immediately makes it possible to inject JavaScript using HTMX functionality. I think this is the weakest point, as htmx works well without unsave-eval. I've been using it in my app without unsafe-eval. The features you lose are just convenience features for writing HTML that you can still achieve by subscribing to htmx events in JS. Yes, it means you have to write a little bit more JS, but it's much better than including unsafe-eval. I wish that htmx would be a bit more CSP-friendly, but it's much better than other similar frameworks.
- hannob 2y agoI feel 2/3 of the comments here are missing the point. CSP is a mitigation for XSS vulnerabilities. Yeah, if you always sanitize everything in the right way, you won't have XSS vulnerabilities. CSP was born out of the recognition that people fail to properly sanitize everything, even if they know that this is what they should do. Because it's complicated, and there are so many corner-cases and different ways to have XSS. CSP is a mitigation on top, in case your "we sanitize everything in the right way" goes wrong. Making the point that you don't need CSP if you don't have XSS vulnerabilities is like saying C is secure as long as you know know how to use it and don't write code with memory safety bugs.
- latent22 2y agoChecks security headers for web server hosting article and finds a F with no headers set
- mtlynch 2y agoThe headers say "Server: AmazonS3" which means it's a static site. Given that it's also a personal blog, there's not much point in CSP headers because a) it's not processing user input and b) even if an attacker achieves XSS, there's no data to steal or useful malicious actions to take on a static personal blog.
- latent22 2y agoYeah the risk here is very low unless they start hosting more complicated content later on. But it is not hosted on S3 and is actually hosted by AWS CloudFront with a S3 origin which now has a built in feature to set security headers for your static site in only a few clicks so you can get that sweet sweet A rating ;)
- deleted 2y ago[deleted]
- ryze20245 2y agoJust don’t use the eval features, inline scripts and properly sanitise user input (if any) and you will mitigate all these issues
- yawaramin 2y agoThis article seems to be full of security vulns that the hypothetical htmx user is deliberately injecting into their own page. Sure, if you deliberately make your app vulnerable, it's vulnerable. This isn't, uh, unique to htmx. For example, sure you can allow htmx on your page to make requests to domains you don't control. This is the proverbial shooting yourself in the foot. If you are allowing this in your site, you have much deeper problems than htmx and need much bigger interventions than CSP.
- latent22 2y agoLets dig in: Loading malicious fragments: This is in no way related to htmx and is the same for all web implementations because you don't go get possible script code from random untrusted domains you don't trust or control. Also if he had tried this with the current version of htmx (2.0) he would have not been able to do this as it now defaults to blocking hx requests to external sites and you can only use local relative paths now. So win to htmx on this point. Unsafe eval: Yeah unsafe eval looks bad but almost every other client side framework also has this same issue and it is very hard to turn this one off on any modern interactive or SPA like website today. Htmx has the option to just ignore the two features that need unsafe eval and implement these features with other more custom solutions unlike most other solutions so I have to chalk this up as a second win for htmx. Disabling HTMX with hx-disable: I think it fair that hx-disable is not a fool proof security feature and is there to stop silly things and provide some isolation for content to separate it from htmx. But you should probably not allow un-sanitized data in here and expect this to save you. Nonces for inline scripts: Yeah htmx has some support for nonces and they can protect from inline scripts inserted into the page somehow but they won't protect you from scripts returned from your trusted local server via hx requests by design. Another small win here. Configuration meta tag: This one is a fair point and the use of malicious meta tags is an interesting attack vector. This may weaken some of the security features built into htmx but if you allow un-sanitized user input to be returned by your server like in his example app there are not many solutions that will come off any better off. Conclusion: When a site uses HTMX, the attack surface of HTML injection is the same as any other SSR solution. It is possible to limit the risk of XSS by using a content security policy. Security is simple and old school as you just sanitize your inputs which all modern backend stacks now make easy. But it not possible to have all HTMX features and provide 100% security against injection (unless you sanitize all inputs and only link to your own server).
- osmano807 2y agoHN really strange, page jumped from front to page 3... I'm still searching for the holy grail of web development without Javascript or TypeScript, still not found. Leptos still ahead but still imature, recently with panic! with signal usage. Dioxus today commited improvements to suspension such as placeholders... egui unusable in mobile, as Android keyboard overlaps the window. Don't know other alternatives in other languages, but for those who don't want JS it's difficult.
- nop_slide 2y agoI was confused by the "Try it examples", they all say "HTMX is working correctly", even the XSS one didn't pop up a JS alert.
- aembleton 2y agoYou can view the source to see what the HTMX code is doing
- OptionOfT 2y agoThis one surprised me: https://www.sjoerdlangkemper.nl/2024/06/26/htmx-content-security-policy/#:~:text=Disabling%20HTMX%20with%20hx%2Ddisable https://www.sjoerdlangkemper.nl/2024/06/26/htmx-content-secu... <div hx-disable> <%= raw(user_content) %> </div> So, I get that `raw` prevents htmx from being used. I get that `<script>` still works. But I find it scary that if `user_content` is `</div><div>...` that is actually injected, as raw HTML. I would expect that the `<%= raw(user_content) %> only has access to contents of the div it is in itself, and nothing more. But instead I understand that the HTML is injected as text (?) and then re-parsed (?).
- Sjoerd 2y agoThis differs for different template engines. In Angular, for example, the template is parsed into a DOM tree, and then template variables are placed in the correct place. This makes injection really hard. In the above example, it would be impossible to break out of the div. Other template engines just do a string search/replace, and this makes injection easy. Then it's indeed possible to break out of the div just by injecting </div>. The example you quoted comes directly from the HTMX docs. They don't specify which template system is used, and I don't immediately recognize the syntax to limit it to a specific template system.
- recursivedoubts 2y agohtmx docs security section: https://htmx.org/docs/#security https://htmx.org/docs/#security and security guide: https://htmx.org/essays/web-security-basics-with-htmx/ https://htmx.org/essays/web-security-basics-with-htmx/
- latent22 2y agohttps://github.com/MichaelWest22/htmx-extensions/tree/main/src/safe-nonce https://github.com/MichaelWest22/htmx-extensions/tree/main/s... one great feature of htmx is how easy it is to understand and develop extensions for. I've just implemented this extension which allows safer handling of CSP nonce if this was required by an application. Hopefully this will get accepted as an official htmx extension. My advice is if your not using inline script tags or the eval feature just keep it simple and disable allowScriptTags and allowEval and set a good CSP header. Also make sure you set a htmx-config meta tag in your page headers to set your config and protect from injected meta tags. If you need inline scripts in a few places then be aware you need to choose a good templating or auto escaping engine on the backend to protect you and think about user inputs and be careful when using any raw escape override functions. If you have a sensitive application that needs regular external pen-testing then look at things like my safe-nonce extension that gives you another layer of protection to sell.