Files
impala/www/log_level.tmpl
Michael Smith 86d33a0a3d IMPALA-11856: Use POST requests to set log level
Set and reset loglevel handlers now require a POST. Implements
Cross-Site Request Forgery (CSRF) prevention in Impala's webserver using
the Double Submit Cookie pattern - where POST requests must include a
csrf_token field in their post with the random value from the cookie -
or a custom header.

CSRF attacks rely on the browser always sending a cookie or
'Authorization: Basic' header.
- With cookies, attacks don't have access to default form values or the
  original cookie, so we can include the cookie's random value in the
  form as a cross-check. As the cookie is cryptographically signed, they
  also can't be replaced with one that would match an attack's forms.
- When not using cookies, a custom header (X-Requested-By) is required
  as CSRFs are unable to add custom headers. This approach is also used
  by Jersey; see
  http://blog.alutam.com/2011/09/14/jersey-and-cross-site-request-forgery-csrf

In a broader implementation this would require a separate cookie so it
can be used to protect logins as well, but login is handled external to
Impala so we re-use the cookie the page already has.

Cookies are now generated for the HTPASSWD authentication method.
Authenticating via JWT still omits cookies because the JWT is already
provided via custom header (preventing CSRF) and disabling
authentication (NONE) means anyone could directly send a request so CSRF
protection is meaningless.

We also start an additional Webserver instance with authentication NONE
when metrics_webserver_port > 0, and the Webserver metric
"impala.webserver.total-cookie-auth-success" can only be registered
once. Additional changes would be necessary to make metric names unique
in Webserver (based on port); for the moment we avoid that by ensuring
all metrics counters are only instantiated for Webservers that use
authentication.

Cookie generation and authentication were updated to provide access to
the random value.

Adds flag to enable SameSite=Strict for defense in depth as mentioned in
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis.
This can be enabled if another CSRF attack method is found.

Verified that this prevents CSRF attacks by disabling SameSite=Strict
and visiting (via https://security.love/CSRF-PoC-Genorator):
```
<html>
  <form enctype="application/x-www-form-urlencoded" method="POST"
        action="http://localhost:45000/set_glog_level">
    <table>
      <tr>
        <td>glog</td>
        <td><input type="text" value="1" name="glog"></td>
      </tr>
    </table>
    <input type="submit" value="http://localhost:45000/set_glog_level">
  </form>
</html>
```

Adds tests for the webserver with basic authentication, LDAP, and SPNEGO
that authorization fails on POST unless
- using a cookie and csrf_token is correctly set in the POST body
- the X-Requested-By header is set

Change-Id: I4be8694492b8ba16737f644ac8c56d8124f19693
Reviewed-on: http://gerrit.cloudera.org:8080/19199
Reviewed-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
2023-01-31 14:40:51 +00:00

97 lines
3.4 KiB
Cheetah

<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
{{>www/common-header.tmpl}}
<style type="text/css">
.log-level{
width: 50%;
line-height: 15px
}
</style>
{{?include_log4j_handlers}}
<h2>Frontend log level configuration (log4j)</h2>
<div class="log-level">
<h5>Current frontend log level:</h5>
<span style="white-space: pre-line">{{get_java_loglevel_result}}</span>
<br>
<form action="set_java_loglevel" method="post">{{>www/form-hidden-inputs.tmpl}}
<div class="form-group" name="level">
<input type="text" class="form-control" name="class" placeholder="e.g. org.apache.impala.analysis.Analyzer">
<br>
<div class="col-xs-20">
<label>Log level:</label>
<select name="level" class="selectpicker" data-style="btn-primary btn-sm">
<option value="all">ALL</option>
<option value="debug">DEBUG</option>
<option value="error">ERROR</option>
<option value="fatal">FATAL</option>
<option value="info">INFO</option>
<option value="off">OFF</option>
<option value="trace">TRACE</option>
<option value="warn">WARN</option>
</select>
<button type="submit" class="btn btn-primary btn-sm">Set Frontend Log Level</button>
</div>
</div>
</form>
<form action="reset_java_loglevel" method="post">{{>www/form-hidden-inputs.tmpl}}
<div class="col-xs-20">
<button type="submit" class="btn btn-primary btn-sm">Reset Frontend Log Levels</button>
<strong>{{reset_java_loglevel_result}}</strong>
</div>
</form>
<br>
{{/include_log4j_handlers}}
<h2>Backend log level configuration (glog)</h2>
<h5>Current backend log level: <span id="glog_text"></span></h5>
<form action="set_glog_level" method="post">{{>www/form-hidden-inputs.tmpl}}
<div class="form-group" name="level">
<div class="col-xs-20">
<label>Log level:</label>
<select name="glog" class="selectpicker" data-style="btn-primary btn-sm">
<option value="0">0 - Off</option>
<option value="1">1 - Info</option>
<option value="2">2 - Debug</option>
<option value="3">3 - All</option>
</select>
<button type="submit" class="btn btn-primary btn-sm">Set Backend Log Level</button>
</div>
</div>
</form>
<form action="reset_glog_level" method="post">{{>www/form-hidden-inputs.tmpl}}
<div class="col-xs-20">
<button type="submit" class="btn btn-primary btn-sm">Reset Backend Log Level</button>
<strong>&nbsp &nbsp Default backend log level: {{default_glog_level}}</strong>
</div>
</form>
<script>
$(document).ready(function() {
$('select[name=glog]').val({{glog_level}});
var text=$('select[name=glog]').children("option:selected").text();
document.getElementById("glog_text").innerHTML = text;
});
</script>
{{>www/common-footer.tmpl}}