|
18 | 18 | // export AUTH_USER=alice AUTH_PASS=hunter2 |
19 | 19 | // ./per_route_auth |
20 | 20 | // |
| 21 | +// TRANSPORT NOTE: HTTP Basic auth sends credentials base64-encoded but |
| 22 | +// NOT encrypted. In production, serve only over TLS (use |
| 23 | +// create_webserver().use_ssl(...)). |
| 24 | +// |
| 25 | +// CONSTANT-TIME NOTE: The credential comparison below uses |
| 26 | +// std::string_view::operator==, which short-circuits on the first |
| 27 | +// differing byte and can leak information via timing side-channels |
| 28 | +// (CWE-208). In production, replace with a constant-time comparison |
| 29 | +// (e.g., CRYPTO_memcmp or an equivalent fixed-length loop). |
| 30 | +// |
21 | 31 | // Then: |
22 | 32 | // |
23 | 33 | // curl -v http://localhost:8080/public # 200 OK |
@@ -81,8 +91,14 @@ int main() { |
81 | 91 | auto h = priv->add_hook(hs::hook_phase::before_handler, |
82 | 92 | std::function<hs::hook_action(hs::before_handler_ctx&)>( |
83 | 93 | [user, pass](hs::before_handler_ctx& ctx) { |
| 94 | + // Null should never occur at before_handler on a matched |
| 95 | + // route, but fail closed (deny) rather than pass on any |
| 96 | + // unexpected null to avoid a fail-open security hole |
| 97 | + // (CWE-636). |
84 | 98 | if (ctx.request == nullptr) { |
85 | | - return hs::hook_action::pass(); |
| 99 | + return hs::hook_action::respond_with( |
| 100 | + hs::http_response::unauthorized( |
| 101 | + "Basic", "private-realm", "Unauthorized")); |
86 | 102 | } |
87 | 103 | std::string_view u = ctx.request->get_user(); |
88 | 104 | std::string_view p = ctx.request->get_pass(); |
|
0 commit comments