• 7 Posts
  • 460 Comments
Joined 2 years ago
cake
Cake day: August 4th, 2023

help-circle

  • Java, Postgres mostly but also LDAP and random in-house-written RESTful services, almost 20 years.

    • The objects we store in the Postgres database are very “hierarchical” in nature, with one top-level object and lots of child/grandchild/great-grandchild objects. (We asked for a Mongo database but the infra team at the time said "make do with Postgres.)
    • As I mentioned, some of that hierarchy is in LDAP or RESTful services, not in Postgres, so we needed something capable of dealing with multiple storage backends that would stitch the objects together as necessary. So the “ORM” needed to have backends for multiple backend systems.
    • We knew clients would need a vast number of different queries. So we made a RESTful endpoint that gave the full power of the ORM to (authorized) clients. If they needed different data, we’d be like “change your query like this” and they didn’t have to wait on us.
    • Early in the project, we consciously designed an extensible JSON representation of our hierarchical objects. That is what’s returned from the aforementioned RESTful endpoint.
    • However, we also created a “shortcuts” system to allow us to “balance” how much of the logic lived on the server vs in the client. (It can mix and match. Like “apply this shortcut, but also filter this way and paginate” or whatever.)
    • We made the API of the ORM such that it could both be used to query from the database/LDAP/RESTful systems, or be used as a client SDK for the aforementioned RESTful query endpoint that the application exposed.
    • It’s both “more than an ORM” (querying from non-database sort of backends) and not fully an ORM (read only, doesn’t handle schema evolution.) But it’s fair to say it’s more “an ORM” than “not an ORM”.
    • The implementation of the Postgres backend part of it is heavily inspired by Django’s ORM.

    We couldn’t have pressed Hibernate into this use case. It doesn’t really deal with hierarchical data and sure as hell doesn’t know how to query from LDAP. I don’t know that anything existed at the time (nor am I sure anything exists now) that would fulfill our use case.

    And the alternative to what we built was a massive, unmaintainable DAO with ridiculous numbers of individual queries in it that would have to be modified or added to endlessly every time someone needed to filter a bit differently or whatever.


  • This was a developed-in-house e-commerce web application at a major e-retailer. So fortunately that monstrosity of a cookie-handling mess was only ever used by one company.

    You know what, though? Talking about this reminds me of another story about the same e-commerce application.

    After a customer placed an order on this e-commerce site, the company’s fraud department had to evaluate the order to make sure it wasn’t fraudulently placed. (As in, with a credit card not owned or authorized for use by the purchaser.) Once that was done, the order had to be communicated to a worker at the warehouse so they could pack the right items into a box, put on a shipping label, and set the box aside to be picked up by the UPS truck which would come once a day near the end of the day.

    The application used by the fraud department and the application that displayed new orders to warehouse workers was one and the same application. Whether a user had fraud-evaluating powers or pack-items-in-boxes powers just depended on what permissions their particular user had. (That may have been decided by LDAP groups. I don’t remember for sure.)

    Meanwhile, the e-commerce site offered gift cards for sale online. The gift card would be shipped to the customer. And there was a box where you could write a message associated with the gift card. So, for instance, someone could buy a gift card to be sent to their nephew’s address or whatever and include a little note like “Happy Birthday. Don’t spend it all at once.” or whatever. And the fraud/pick-and-pack application would display all details of the order including any messages associated with the gift cards.

    Well, I found a stored cross-site scripting vulnerability where if you put <script>...</script> tags with some JavaScript in the gift card message box and completed the order, the JavaScript would execute any time someone viewed the details page for the order in the fraud/pick-and-pack application. And of course, the JavaScript could do within that application just about anything the user could do with their given permissions.

    The main danger was that a malicious actor with sufficient knowledge of how our fraud application worked could place an order fraudulently with someone else’s credit card and include in the order a gift card with a malicious JavaScript payload in the message box, and then that malicious JavaScript could automatically mark the order “a-ok, no fraud here” when a fraud department worker loaded the order details page, letting the order be fulfilled without any actual fraud review.

    The fix was pretty simple. Just stick a <c:out>...</c:out> in the appropriate place in the fraud/pick-and-pack application code. But it was an interesting example of a vulnerability in a not-customer-facing application that could none-the-less be exploited by any public customer/user without any particular special access.

    If you’re interested in one more interesting story about the same e-commerce application, see this comment I made a while ago.



  • Java webapp. Customer facing. E-commerce application, so in PCI scope and dealt with credit card info and such.

    There was one specific cookie that stored some site-wide preference for the customer. (Why not just put that preference in the database associated with the user? Because that would make too much sense is why.)

    But the way they encoded the data to go into the cookie? Take the data, use the Java serialization framework (which is like Python’s “Pickle” or Go’s “Gob”) to turn that into a string. But that string has binary data in it and raw binary data is kindof weird to put in a cookie, so you base64 encode the result. (The base64 encoding was the only sane step in the whole process.) Then you do the reverse when you receive the cookie back from the browser. (And no, there was no signature check or anything.)

    The thing about the Java serialization framework, though is that decoding back into Java objects runs arbitrary object constructors and such. As in, arbitrary code execution. And there’s no checking in the deserialization part of the Java serialization framework until your code tries to cast the object to whatever type you’re expecting. And by that point, the arbitrary code execution has already happened. In short, this left a gaping vulnerability that could easily have been used to extremely ill effect, like a payment information breach or some such.

    So all a malicious user had to do to run arbitrary code on our application server was serialize something, base64 encode it, and then send it to our servers as a cookie value. (Insert nail biting here.)

    When we found out that there was a severe vulnerability, I got the task of closing the hole. But the existing cookies had to continue to be honored. The boss wasn’t ok with just not honoring the old cookies and developing a new cookie format that didn’t involve the Java serialization framework.

    So I went and learned enough about the internal workings of how the Java serialization framework turned a Java value into a binary blob to write custom code that worked for only the subset of the Java serialization format that we absolutely needed for this use case and no more. And my custom code did not allow for arbitrary code execution. It was weird and gross and I made sure to leave a great big comment talking about why we’d do such a thing. But it closed the vulnerability while still honoring all the existing cookies, making it so that customers didn’t lose the preference they’d set. I was proud of it, even though it was weird and gross.

    The value that was serialized to put into the cookie? A single Java int. Not a big POJO of any sort. Just a single solitary integer. They could just as well have “serialized” it using base-10 rather than using the Java serialization framework plus base64.




  • Not exactly the densest material out there, but pennies are cheap and easily procured. May not be quite what you’re looking for for your use case. (You asked about “cost/weight ratio” and “weight to space” which makes it sound like you’re looking to add a lot of weight.)

    I’ve been known to make a fully-enclosed cylindrical cavity and set my slicer to pause at exactly the right layer to where I can drop a few stacks of pennies into the print before upper layers seal the cavity closed.




  • I can definitely see a lot of good applications for this way of doing things.

    It does seem like I often run across “error handling” code that literally just catches a bunch of different exception types and throws a new exception with the same content from the caught error just reworded, adding literally zero helpful information in the process.

    It’s definitely the case that sometimes the exact sort of crash you’d get if you didn’t handle errors is exactly the best sort of exception output the program could do given its particular use case and target audience. Or at least it might be best to let the error be handled much further away in the call stack.





  • I can’t imagine you’re the only one in this situation. If I were in your shoes, I’d search for similar stories online and see if I could get a sense of how friendly the company is to swapping OSs. For some companies, changing the OS is a complete deal breaker. Other companies are pretty willing to assume the issue was indeed strictly hardware and had nothing to do with changing the OS, and thus will go ahead and do the repair.

    If you find that company is more like the former, install Windows. If not, just start the warranty repair process.


  • As others have said, you’re changing the topic talking about FUTO’s license in a response to a comment about the AGPL.

    But to continue your thread:

    If you ask them to articulate their concern, I haven’t heard one that isn’t on the lines of “I want to be able to use this code in my paid product”…

    I specifically want anyone to be allowed to use any and all FOSS software I write (and I do write and publish some) commercially, so long as they abide by the terms of the license I choose. (Typically the AGPLv3.)

    If, for instance, a mainstream commercial consumer electronics device incorporated my code into the firmware and because my code is under the AGPLv3, end users had the legal right to demand the means to modify the behavior of their devices to better suit them, I’d be thrilled.

    Plus, if a company with an IT department is distributing a modified version of my code, that might well include some improvements generally useful for all/most/many users of my project. And if my projects is under the AGPLv3, I can demand a copy of the source code of their modified version and incorporate any improvements back upstream into my project so all users of my FOSS project can benefit from it.

    Commercial redistribution is more of a feature than you think. I think you’re missing the point of copyleft.


  • Nothing about copyleft causes the “owner” to not hold the copyright on a work.

    Copyright gives the holder (either the author or the party to which the copyright is assigned) a few specific (but broad) exclusive rights to the work: reproduction, preparation of derivative works, distribution, public performance (which probably doesn’t so much apply to software), and public display (also not applicable to software, so much). (And then there’s circumvention, but that’s yucky and irrelevant to this case, so we’ll ignore it.)

    “Exclusive” means nobody is allowed to do any of those things except the copyright holder (unless the copyright holder licenses those rights to others, but we’ll get to that.)

    The copyright holder can give/sell/transfer the copyright to someone else (in which case the previous holder is now excluded from doing with the work all the things in the first paragraph above because someone else now holds all those exclusive rights), but that’s not what the AGPL does.

    The copyright holder can also license any or all of the exclusive rights in the first paragraph to some person or party (or in the case of an “open license” like the AGPL, to everyone).

    The AGPL licenses rights like distribution and preparation of derivative works to others (under certain conditions(/covenants) like “you can only distribute copies if you do so under the same license as you got it under”).

    So, if some hypothetical party named “Bob” started a project, they’d hold the copyright. If Bob put the AGPL on that project and also required any contributor to assign copyright on their specific contributions to Bob, Bob would hold the copyright on the entire project code, including all contributions. Someone else could take advantage of the terms of the AGPL allowing derivative works and redistribution to create their own fork (so long as they abided by the conditions(/covenants) in the AGPL), and if they did so, they could omit on their fork any copyright assignment requirement, in which case the fork could end up owned by a mishmash of different copyright holders (making it hard to impossible for the administrator of the fork to do anything tricky like changing what license future versions were under.)

    However, on Bob’s original (non-fork) version, if Bob, as the copyright holder, changes the license file to something proprietary, Bob has (arguably?) created a new work that is not the same work as the previous version, and Bob can license that new version under a different license. (I suppose one might be able to argue that changing just the license file isn’t legally enough to make a new version, but the very next time a nontrivial change was made to the codebase, that would qualify as a new version, so it kindof doesn’t matter.) Bob has already licensed previous versions of his non-fork under the AGPL, so Bob can’t really rescind that license already granted on older versions. But new versions could indeed be put under a different license. (Mind you, there are licenses that have specific terms that make them rescindable on old versions. Take for instance the Open Gaming License fiasco that WotC tried to pull not terribly long ago. But I don’t think the AGPL is a license that can be rescinded.)

    Since Bob can’t rescind the license on older versions, if Bob made a future version proprietary, the community or any particular party that wanted to could take the last AGPL version of the non-fork and make a fork from there that remained under the AGPL.

    The moral of the story is: if you don’t want the copylefted code project you start to be changed to a proprietary license later, don’t do any copyright assignment agreement. The codebase being owned by a diverse mishmash of different copyright holders is a feature, not a bug.

    And, as mentioned elsewhere in this post, Immich is owned by a lot of different copyright holders as it has no copyright assignment requirement.


  • Can you name one other personality with a large following that comes even close to Louis Rossmann in bringing stuff to light and fighting back against enshittification?

    Well, there’s Corey Doctorow, of course. He literally wrote the book on Enshittification.

    There are definitely more “behind the scenes” folks doing a lot for that particular cause who don’t so much have a following of anywhere near the same size, but nonetheless do fight enshittification in big ways. Bradley Kuhn comes to mind.



  • From what I’m seeing, you’re right. If there was a contributor assignment policy (some official policy associated with Immich saying that by submitting a PR, you agree to assign copyright on your code changes go the Immich project), FUTO could change the license on future versions as they wished. But it doesn’t look like there’s any contributor assignment or contributor license agreement on Immich.

    To be pedantic, Immich did change from MIT to AGPLv3 a while ago. FUTO could technically scrap the current version, grab the last MIT version of the code, relicense it under their “source-first” license (or any other license they like, pretty much), and declare “this is now the official development version of Immich from which new releases will come.” That would be drastic even for FUTO, though (I don’t think that’s likely any time soon), and the community could then fork the latest AGPLv3 version with a different name and carry on with development.