简体   繁体   English

使用基于表单的 ldap 身份验证在 apache 反向代理上登录 CSRF 保护

[英]Login CSRF protection on an apache reverse proxy with form based ldap authentication

We have a reverse proxy who handles the user authentication using a form and ldap authentication.我们有一个反向代理,它使用表单和 ldap 身份验证处理用户身份验证。 This is working fine.这工作正常。

Now, i am asked to implement CSRF login protection, described here: https://support.detectify.com/support/solutions/articles/48001048951-login-csrf现在,我被要求实施 CSRF 登录保护,描述如下: https : //support.detectify.com/support/solutions/articles/48001048951-login-csrf

I read the easiest way is to implement Double submit Cookies, where when the form is loaded a token is generated and passed within the response to the user.我读到的最简单的方法是实现 Double submit Cookies,当加载表单时,会生成一个令牌并在响应中传递给用户。 When the user submits the form, the form then checks if the cookie is the same.当用户提交表单时,表单会检查 cookie 是否相同。

I cannot use this implementation because the form does not handle the authentication, but the mod_auth_form module does.我无法使用此实现,因为表单不处理身份验证,但 mod_auth_form 模块可以。 Here is our setup:这是我们的设置:

vhost config:虚拟主机配置:

<VirtualHost *:80>
  ServerName test.example.com
  RewriteEngine On
  RewriteCond %{HTTPS} off
  RewriteRule (.*) https://%{SERVER_NAME}$1 [R,L]
</VirtualHost>
<VirtualHost *:443>
  ServerName test.example.com
  SSLEngine on
  SSLCipherSuite AES256+EECDH:AES256+EDH
  SSLProtocol All -SSLv2 -SSLv3
  SSLHonorCipherOrder On
  SSLCompression off
  SSLCertificateFile test.example.com.cer
  SSLCertificateKeyFile test.example.com.key
  SSLCertificateChainFile test.example.com.ca
  Alias "/auth" "/var/www/auth"
  Customlog /var/log/apache2/test.example.com-access.log combined
  ErrorLog /var/log/apache2/test.example.com-error.log
  SSLProxyEngine on
  SetEnvIfNoCase Request_URI "^/auth/" noauth
  <Location /auth/logout>
    SetHandler form-logout-handler
    AuthType form
    AuthName realm
    AuthFormLogoutLocation /
    Session On
    SessionCookieName session path=/
  </Location>
  <Location />
    AuthType form
    AuthFormProvider ldap
    AuthName realm
    AuthFormLoginSuccessLocation %{REQUEST_URI}
    Session On
    SessionCryptoPassphrase secretphrase
    SessionCookieName session path=/
    <RequireAny>
      Require ldap-group CN=webapp_users,OU=Groups,DC=example,DC=com
      Require env noauth
    </RequireAny>
    ErrorDocument 401 "/auth/login.html"
    AuthLDAPBindDN ldap@example.com
    AuthLDAPBindPassword secretpass
    AuthLDAPURL "ldap://example.com/OU=Users,DC=example,DC=com?sAMAccountName,displayName?sub"
    AuthLDAPMaxSubGroupDepth 5
    AuthLDAPGroupAttribute member
    AuthLDAPSubgroupAttribute member
    AuthLDAPSubGroupClass group
  </Location>
  ProxyPass /auth/ !
  ProxyPreserveHost On
  ProxyPass               /             https://webapp.example.com/
  ProxyPassReverse        /             https://webapp.example.com/
  ProxyRequests           Off
  AllowEncodedSlashes     NoDecode
  Header always append X-Frame-Options SAMEORIGIN
</VirtualHost>

And the login form looks like:登录表单如下所示:

<html>
  <head>
    <title></title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="mobile-web-app-capable" content="yes">
    <link href='https://fonts.googleapis.com/css?family=Roboto+Condensed:300' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" type="text/css" href="auth/css/style.css" />
    <link rel="icon" href="auth/assets/example_com.ico" />
    <script type="text/javascript">
      function init() {
        var sitename = window.location.hostname;
        document.getElementById("sitename").innerHTML =sitename;
        document.title = sitename;
        document.getElementById("username").focus();
      }

      function tryLogin() {
        localStorage.setItem("tryLogin", true);
      }
    </script>
  </head>
  <body onload="init()">
      <div id=wrap-logo>
        <div id=logo></div>
      </div>
    <div id="content">
      <h1><div id='sitename'>empty</div> requires a login</h1>
      <form method="POST" action="" onsubmit="tryLogin()" autocomplete="off">
        <label for="username">Username</label><input type="text" id="username" name="httpd_username" placeholder="Username" value="" />
        <label for="password">Password</label><input type="password" id="password" name="httpd_password" placeholder="Password" value="" />
        <input type="submit" name="login" value="Login" />
      </form>
    </div>
  </body>
</html>

So, basically what happens here;所以,基本上这里发生了什么; If you are not logged in, you are redirected to the 401 errorpage which is the login page.如果您没有登录,您将被重定向到 401 错误页面,即登录页面。 When you submit the form, the authentication credentials are passed to the mod_ldap module which creates a session cookie if authenticated properly.当您提交表单时,身份验证凭据将传递给 mod_ldap 模块,如果身份验证正确,该模块会创建会话 cookie。 After that, anything but /auth/* is proxied to the destination.之后,除了 /auth/* 之外的任何内容都被代理到目的地。

Is there any way i could implement CSRF login protection in this setup?有什么办法可以在这个设置中实现 CSRF 登录保护吗?

I have tried mod_csrf , but can't get it to work, and i'd rather not use it because its an alpha release.我试过mod_csrf ,但不能让它工作,我宁愿不使用它,因为它是一个 alpha 版本。

I mod_csrf is impossible together with the mod_auth_form because mod_auth_form will always handle your request first.我 mod_csrf 不可能与 mod_auth_form 一起使用,因为 mod_auth_form 将始终首先处理您的请求。

Just install php on your apache server and do like the link you send.` $token = bin2hex(openssl_random_pseudo_bytes(16));只需在您的 apache 服务器上安装 php 并像您发送的链接一样。` $token = bin2hex(openssl_random_pseudo_bytes(16)); setcookie("CSRFtoken", $token, time() + 60 * 60 * 24); setcookie("CSRFtoken", $token, time() + 60 * 60 * 24);

        <form action="loginchecker.php" method="post">
            <input name="user">
            <input name="pass" type="password">
            <input name="CSRFtoken" type="hidden" value="' . $token . '">
            <input type="submit">
        </form>;`

You can redirect the form to a page that check if the token en cookie are correct then fill with this page a new form and send it directly with js.您可以将表单重定向到检查令牌 en cookie 是否正确的页面,然后在此页面中填写一个新表单并直接使用 js 发送。 document.forms["loginFormname"].submit();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM