This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-10-03
Channels
- # babashka (5)
- # beginners (34)
- # biff (3)
- # calva (29)
- # cherry (11)
- # cider (7)
- # clojure (148)
- # clojure-brasil (1)
- # clojure-europe (16)
- # clojure-nl (1)
- # clojure-norway (6)
- # clojure-uk (6)
- # clojuredesign-podcast (8)
- # clojurescript (49)
- # cursive (1)
- # datalevin (7)
- # fulcro (1)
- # honeysql (1)
- # jobs (1)
- # matrix (7)
- # off-topic (13)
- # re-frame (12)
- # react (21)
- # reagent (42)
- # releases (6)
- # remote-jobs (2)
- # shadow-cljs (9)
- # solo-full-stack (5)
- # sql (7)
- # squint (9)
- # vim (2)
- # xtdb (11)
- # yamlscript (5)
Hi! =
works for string equality, (= "abc" "abc")
, but is not secure against timing attacks. Does anyone have a go-to constant time string comparison in Clojure?
Looks like James Reeves has a solution: https://github.com/weavejester/crypto-equality/tree/master
I am not a security consultant, but my understanding was this was originally a problem and later fixed in MessageDigest.isEquals
- so assuming you check your specific JVM runtime version, perhaps you can use the builtin?
As a non-security person, I do wonder: if you're seriously worried about timing attacks, can you be sure the code posted above doesn't get mangled by the JIT to a more "optimized" version at some point? And is there a good paranoid solution that doesn't end up relying on checking actual clocks and sleeping/jittering?
> I am not a security consultant, but my understanding was this was originally a problem and later fixed in MessageDigest.isEquals
- so assuming you check your specific JVM runtime version, perhaps you can use the builtin?
Looks like you’re right, and that this problem was fixed in java 1.6.0_17 (6u17)?
. I’m fortunately running a more recent java version! 😄
> As a non-security person, I do wonder: if you’re seriously worried about timing attacks, can you be sure the code posted above doesn’t get mangled by the JIT to a more “optimized” version at some point? And is there a good paranoid solution that doesn’t end up relying on checking actual clocks and sleeping/jittering?
Yup, I’m worried about the exact same thing. A colleague told me that in other ecoystems, constant time string comparison is implemented in assembly to avoid this “optimization”.
Using the platform for this (`java.security.MessageDigest/isEqual`) makes sense to me. I’m not a security expert either, but I try to make well-informed choices. I didn’t know this was part of the platform at all, TIL!
Thank you! 💯
>> As a non-security person, I do wonder: if you’re seriously worried about timing attacks, can you be sure the code posted above doesn’t get mangled by the JIT to a more “optimized” version at some point? And is there a good paranoid solution that doesn’t end up relying on checking actual clocks and sleeping/jittering? > > Yup, I’m worried about the exact same thing. A colleague told me that in other ecoystems, constant time string comparison is implemented in assembly to avoid this “optimization”. Though I hesitate to imply that anything is wrong with James Reeves’ code. The library is supposed to solve exactly this problem. From the README: > A very small Clojure library for protecting against https://en.wikipedia.org/wiki/Timing_attack when comparing strings or sequences of bytes. > This is useful for comparing user-supplied values against secrets held by the application, such as tokens or keys.
I never meant to imply the library works incorrectly, in fact it seems to work on the same idea: https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/security/MessageDigest.java#L490-L494 Just that if security is concerned, something that is tracked and pinned to a specific JVM version may be more appropriate, since it far more likely that (from the JVM's perspective) random Clojure code gets compiled/rewritten/JIT'ed to something you don't want.
Interestingly, looks like the Clojure library always exits quickly on different length strings, unlike the JVM version.
Yeah, I was slightly surprised by that too. I suspect that overall, string length has less of a security impact than being able to guess correct digits in the real string. Which is how how timing attacks work (if I understand it correctly). Still, surprising.
> Interestingly, looks like the Clojure library always exits quickly on different length strings, unlike the JVM version. Did you compare string literals or strings of unknown (to the compiler) size? --- This discussion got me interested. I have very little experience in that area, so I have a naive question: Why would you be concerned about timing attacks on such a low level? Shouldn't the timing be constant at an interface level, where the actual user interacts?
> Why would you be concerned about timing attacks on such a low level? Shouldn't the timing be constant at an interface level, where the actual user interacts?
>
Can you give a specific example of what you're proposing?
I suppose it is possible to protect against timing attacks further up the stack. But I don't see what benefit that gives. To me, using a constant time =
function seems like the simplest solution to this problem.
Not directly but I've implemented (implicit) throttling before to filter out bot spam and similar stuff. But that was always way up the stack so to speak. I think of these kinds of things as a concern of the interface and not the internal logic. This seems related. But if it's at the level of the actual string comparison, then you get the benefit of not having to worry about who, when and where it gets called. Feels more "done" and is less likely to regress. So I agree with you thanks!
Hello! I’m running an application in a container with 2GB of memory but it’s OOMing at less than half that. Is setting the MaxRAMPercentage
JVM option (for example with -XX:MaxRAMPercentage=90
) the recommended way to go about using more of the container’s memory? This is the only application running in the container so it won’t stomp on anything by increasing its memory usage. I have UseContainerSupport
enabled as well if that changes anything.
Yes, that is the recommended way of setting memory use in a container. I typically use the following in a Dockerfile
configuration
ENV JDK_JAVA_OPTIONS "-XshowSettings:system -XX:+UseContainerSupport -XX:MaxRAMPercentage=85"
https://practical.li/engineering-playbook/continuous-integration/docker/clojure-multi-stage-dockerfile/#java-virtual-machine-optimisationcool, thank you!
UseContainerSupport isn’t usually needed (it’s an old flag) For MaxRAMPercentage, 90% is quite aggressive- it may work but make sure you properly test your app. JVM also consumes non-heap memory (thread stacks, gc, jit, metaspace, etc)

I dropped it to the 85% recommended in the URL above — is that still too aggressive do you think?
I've used 85% as the default on several commercial projects and haven't had any issues I only consider changing it if there are performance issues with that setting Much can depend on what the application itself is doing inside the container. As the original post mentioned out of memory messages, then it suggests some analysis is required
Visual VM is a fairly easy tool to use to start seeing if and where there may be issues There are some other useful tools too https://practical.li/clojure/reference/jvm/profile-tools/

Hi guys, I'm studying programming paradigms and I'm working with Clojure, I'm trying to make a filter function, but I can't get the desired return, could someone help me? (defn filtro [arr] (let [state (atom arr)] (fn [tit] (swap! state (fn [s] (filter #(or (<= (count tit) 0) (not (nil? (re-find (re-pattern (str tit)) (:titulo %))))) s))) (fn [fcomp] (swap! state (fn [s] (filter #(or (nil? fcomp) (fcomp (:categoria %))) s))) (fn [cat] (swap! state (fn [s] (filter #(or (<= (count cat) 0) (= cat (:categoria %))) s))) @state))))) this is the data (def dados [{:titulo "Livro 1", :categoria "Ficção"} {:titulo "Livro 2", :categoria "Não Ficção"} {:titulo "Livro 3", :categoria "Ficção"} {:titulo "Livro 4", :categoria "Não Ficção"}]) this is what I'm trying to do (def filtrar-dados (filtro dados)) (def dados-filtrados-1 (filtrar-dados "Livro 1"))
It would help us help you if you provided the following: what it is you're trying to do, the inputs, the expected output and the actual output. It also helps to know what you tried and what you found.
this is the data (def dados [{:titulo "Livro 1", :categoria "Ficção"} {:titulo "Livro 2", :categoria "Não Ficção"} {:titulo "Livro 3", :categoria "Ficção"} {:titulo "Livro 4", :categoria "Não Ficção"}]) this is what I'm trying to do (def filtrar-dados (filtro dados)) (def dados-filtrados-1 (filtrar-dados "Livro 1"))
Thanks. I see. It seems that filtrar-dados is a function that operates on the dados data. And dados-filtrados-1 is data that results from filtering dados for "Livro 1". Now, what did you expect? And what did you actually get? What did you try to figure out the problem?
If I try to print the filtered data, this error is returned
That is not an error. What do you expect if you call (filtrar-dados)
?
By the way, the result you show is not an error. Clojure is saying that the filtered data is a function. This is the way Clojure prints out a function object. The reason you know it is a function is because of the "...$fn__nnn...". This is an anonymous function. Which is harder to debug. If you replace all "(fn [x] ...)" by "(fn somename [x]...)" you'll get a better idea of which function it is.
this would be the return message :titulo "Livro 1", :categoria "Ficção"
^^^ Yes. and to expound on that. Your code expects 3 nested function calls. Highly unrecommended. Here is a hint on how to get the return value you probably expect
(first ((((filtro dados) "Livro 1") nil) []))
https://clojure.org/guides/learn/functions#_multi_arity_functions are preferred over such a design
@U05ULEF26BH It would make your code a lot more readable if you used triple backticks around blocks of code, so it looked like this:
(defn filtro [arr]
(let [state (atom arr)]
(fn [tit]
(swap! state (fn [s]
(filter #(or (<= (count tit) 0)
(not (nil? (re-find (re-pattern (str tit)) (:titulo %)))))
s)))
(fn [fcomp]
(swap! state (fn [s]
(filter #(or (nil? fcomp)
(fcomp (:categoria %)))
s)))
(fn [cat]
(swap! state (fn [s]
(filter #(or (<= (count cat) 0)
(= cat (:categoria %)))
s)))
@state)))))
this is the data
(def dados
[{:titulo "Livro 1", :categoria "Ficção"}
{:titulo "Livro 2", :categoria "Não Ficção"}
{:titulo "Livro 3", :categoria "Ficção"}
{:titulo "Livro 4", :categoria "Não Ficção"}])
this is what I'm trying to do
(def filtrar-dados
(filtro dados))
(def dados-filtrados-1
(filtrar-dados "Livro 1"))
It's really hard to tell from your code what you are trying to do. Stateful code like that isn't idiomatic in Clojure in general (there are some cases where state is needed but it isn't in this case). Are you trying to find a book by title in a list of books?
(defn by-title [books title]
(first (filter (fn [book] (= title (:titulo book))) books)))
(by-title dados "Livro 1")
user=> {:titulo "Livro 1", :categoria "Ficção"}