Clojure中的安全管理器 [英] Security Manager in Clojure

查看:151
本文介绍了Clojure中的安全管理器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我试着从Clojure程序安装一个安全管理器,并且在一个好的开始后卡住。这个对我来说在Clojures简单的REPL, Lein REPL,以及在Emacs的Cider REPL中。它禁止使用(System / exit n)。

 (def SM(proxy [SecurityManager] [] 
(checkPermission
[^ java.security.Permission p]
(when(.startsWith(.getName p)exitVM)
(throw(SecurityException。exit)))))) )

(System / setSecurityManager SM)

但我想这样做安全经理做更多。例如。记录任何访问。令人惊讶的是,许多Clojure函数似乎调用安全管理器,因此,当在其内部使用时,给出一个无限循环,也称为StackOverflowException。



我失败的尝试:

 (def security-log(atom()))

(def SM(proxy [SecurityManager]
(checkPermission
([^ java.security.Permission p]
(let [now(.toString(System / currentTimeMillis))
log(str[now] [cp / 1] SM要求p]
(swap!security-log conj))
(当.startsWith(.getName p)exitVM)
(throw(SecurityException。exit))))
([^ java.security.Permission p ^ Object o]
(let [now(.toString(System / currentTimeMillis))
log(str
[now]
[cp / 2] SM被要求输入pono)]
security-log conj log))))))

(System / setSecurityManager SM)


$ b



这两个问题都没有成功,因此我有两个问题。


  1. 我做错了什么?

  2. 有一个系统的(和简单的)方式,我可以找到哪些功能,

    解决方案

    添加<$ c $后, c>(println(.getName p))到第一个 checkPermission()实现,我发现导致循环的权限是 createClassLoader suppressAccessChecks (请参阅此处有关可用权限的详细列表)。当评估REPL中的单个表达式时,我得到以下结果:

      createClassLoader 
    createClassLoader
    createClassLoader
    suppressAccessChecks

    Clojure创建一个新的 DynamicClassLoader 通过 RT.makeClassLoader()用于 clojure.lang.Compiler 类的以下方法: eval compile1 load 。当在REPL上工作时,每个表达式都是 eval ed,以便触发 createClassLoader 权限和 suppressAccessChecks 由使用反射触发,这在Clojure中很常见。



    仍然我无法确定如何生成循环,所以我添加了一个(Thread / dumpStack)名称打印后获得 作为输出。 gist只表示它第一次开始循环。循环的原因是,当执行反射时,似乎有一个优化(至少在 sun.reflect.DelegatingClassLoader 的初始化,因此许可权限是Oracle的JVM 和OpenJDK) createClassLoader 被检查,(。toString ,,,)的反映完成,等等...

    这是有意义的,因为前一次表达式 eval 'ed在一个新的REPL循环不会出现,只有经过几次评估相同的表达式循环开始,这是优化时启动。



    我发现的解决方法涉及使用Clojure的东西只有当权限不是 suppressAccessChecks createClassLoader 。只过滤一个或另一个导致循环出现,我很确定它可能与相同的问题相关,但我没有检查在这些情况下的堆栈跟踪。

     (def SM(proxy [SecurityManager] [] 
    (checkPermission
    ([^ java.security.Permission p]
    ;;没有反射或ClassLoader创建
    ;;涉及使用Clojure代码。
    (when-not(#{suppressAccessCheckscreateClassLoader}(.getName p))
    (let [now toString(System / currentTimeMillis))
    log(str[now][cp / 1] SM要求p]
    (swap!security-log conj日志)
    (when(.startsWith(.getName p)exitVM)
    (throw(SecurityException。exit))))))))
    pre>

    EDIT



    是避免在 checkPermission 方法中包含的代码中的反射,这可以通过在(。toString ,, ,)方法调用!

     (def SM(proxy [SecurityManager] [] 
    (checkPermission
    ([^ java.security.Permission p]
    (let [now(.toString ^ Object(System / currentTimeMillis))
    log(str[now] [cp / 1] SM要求p]
    (swap!安全日志conj))
    (when(.startsWith(.getName p)exitVM)
    (throw(SecurityException。exit)))))))


    I try to install a security manager from a Clojure program, and am stuck short after a good start.

    This one works for me in Clojures simple REPL, in the Lein REPL, and in the Cider REPL in Emacs. It prevents the use of (System/exit n).

    (def SM (proxy [SecurityManager] [] 
              (checkPermission 
                [^java.security.Permission p] 
                (when (.startsWith (.getName p) "exitVM") 
                  (throw (SecurityException. "exit")))))) 
    
    (System/setSecurityManager SM)
    

    But I want to do this security manager to do more. E.g. log any access. Surprisingly many Clojure functions seem to call the security manager, and thus, when used inside of it, give an infinite loop, aka StackOverflowException.

    My failed try:

    (def security-log (atom ())) 
    
    (def SM (proxy [SecurityManager] [] 
              (checkPermission 
                ([^java.security.Permission p] 
                   (let [now (.toString (System/currentTimeMillis)) 
                         log (str "[" now "] " "[cp/1] SM is asked for " p)] 
                     (swap! security-log conj log)) 
                   (when (.startsWith (.getName p) "exitVM") 
                     (throw (SecurityException. "exit")))) 
                ([^java.security.Permission p ^Object o] 
                   (let [now (.toString (System/currentTimeMillis)) 
                         log (str 
                               "[" now "] " 
                               "[cp/2] SM is asked for " p " on " o)] 
                     (swap! security-log conj log)))))) 
    
    (System/setSecurityManager SM) 
    

    Both failed, putting the log into an atom, and just printing it.

    So I have two questions.

    1. Am I doing something wrong?
    2. Is there a systematic (and easy) way I can find out which functions I can use inside of a security manager, without putting it into a loop?

    解决方案

    After adding a (println (.getName p)) to the first checkPermission() implementation, I found that the permissions that cause the loop are createClassLoader and suppressAccessChecks (see here for a detailed list on the permissions available). When evaluating a single expression in the REPL I got the following:

    createClassLoader
    createClassLoader
    createClassLoader
    suppressAccessChecks
    

    Clojure creates a new DynamicClassLoader through RT.makeClassLoader() which is used in the following methods of the clojure.lang.Compiler class: eval, compile1 and load. When working on the REPL every expression is evaled so that triggers the createClassLoader permission and the suppressAccessChecks are triggered by the use of reflection, which is common in Clojure.

    Still I couldn't figure out exactly how the loop was being generated so I added a (Thread/dumpStack) after the name printing and got this as the output. The gist represents only the first time it starts looping. The cause of the loop is that when performing reflection there seems to be an optimization (at least in Oracle's JVM and OpenJDK) where the initialization of a sun.reflect.DelegatingClassLoader is involved, so the permission createClassLoader is checked, the reflection for (.toString ,,,) is done and so on...

    This makes sense since the first few times an expression is eval'ed in a fresh REPL the loop does not appear, only after a few times of evaluating the same expression the loop starts, which is when the optimization kicks in.

    The workaround I found involves using Clojure stuff only when the permission is not suppressAccessChecks or createClassLoader. Filtering only one or the other causes the loop to appear, I'm pretty sure it might be related to the same issue but I didn't check the stack traces in those cases.

    (def SM (proxy [SecurityManager] [] 
              (checkPermission 
                ([^java.security.Permission p] 
                  ;; When there's no Reflection or ClassLoader creation
                  ;; involved use Clojure code.
                  (when-not (#{"suppressAccessChecks" "createClassLoader"} (.getName p))
                     (let [now (.toString (System/currentTimeMillis))
                           log (str "[" now "] " "[cp/1] SM is asked for " p)] 
                       (swap! security-log conj log)))
                  (when (.startsWith (.getName p) "exitVM")
                    (throw (SecurityException. "exit")))))))
    

    EDIT

    A much better solution is to avoid reflection in the code you include in the checkPermission method, which can be accomplished by just adding a type hint in the (.toString ,,,) method call!

    (def SM (proxy [SecurityManager] [] 
              (checkPermission 
                ([^java.security.Permission p] 
                  (let [now (.toString ^Object (System/currentTimeMillis))
                        log (str "[" now "] " "[cp/1] SM is asked for " p)] 
                  (swap! security-log conj log))
                (when (.startsWith (.getName p) "exitVM")
                  (throw (SecurityException. "exit")))))))
    

    这篇关于Clojure中的安全管理器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆