comparison src/http/ngx_http_core_module.c @ 7638:681b78a98a52

The new auth_delay directive for delaying unauthorized requests. The request processing is delayed by a timer. Since nginx updates internal time once at the start of each event loop iteration, this normally ensures constant time delay, adding a mitigation from time-based attacks. A notable exception to this is the case when there are no additional events before the timer expires. To ensure constant-time processing in this case as well, we trigger an additional event loop iteration by posting a dummy event for the next event loop iteration.
author Ruslan Ermilov <ru@nginx.com>
date Wed, 08 Apr 2020 01:02:17 +0300
parents f001d9384293
children 43a0a9e988be 5b7ec588de48
comparison
equal deleted inserted replaced
7637:0cb942c1c1aa 7638:681b78a98a52
18 18
19 #define NGX_HTTP_REQUEST_BODY_FILE_OFF 0 19 #define NGX_HTTP_REQUEST_BODY_FILE_OFF 0
20 #define NGX_HTTP_REQUEST_BODY_FILE_ON 1 20 #define NGX_HTTP_REQUEST_BODY_FILE_ON 1
21 #define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2 21 #define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2
22 22
23
24 static ngx_int_t ngx_http_core_auth_delay(ngx_http_request_t *r);
25 static void ngx_http_core_auth_delay_handler(ngx_http_request_t *r);
23 26
24 static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r); 27 static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r);
25 static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r, 28 static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r,
26 ngx_http_location_tree_node_t *node); 29 ngx_http_location_tree_node_t *node);
27 30
518 ngx_conf_set_enum_slot, 521 ngx_conf_set_enum_slot,
519 NGX_HTTP_LOC_CONF_OFFSET, 522 NGX_HTTP_LOC_CONF_OFFSET,
520 offsetof(ngx_http_core_loc_conf_t, satisfy), 523 offsetof(ngx_http_core_loc_conf_t, satisfy),
521 &ngx_http_core_satisfy }, 524 &ngx_http_core_satisfy },
522 525
526 { ngx_string("auth_delay"),
527 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
528 ngx_conf_set_msec_slot,
529 NGX_HTTP_LOC_CONF_OFFSET,
530 offsetof(ngx_http_core_loc_conf_t, auth_delay),
531 NULL },
532
523 { ngx_string("internal"), 533 { ngx_string("internal"),
524 NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, 534 NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
525 ngx_http_core_internal, 535 ngx_http_core_internal,
526 NGX_HTTP_LOC_CONF_OFFSET, 536 NGX_HTTP_LOC_CONF_OFFSET,
527 0, 537 0,
1122 } 1132 }
1123 } 1133 }
1124 1134
1125 /* rc == NGX_ERROR || rc == NGX_HTTP_... */ 1135 /* rc == NGX_ERROR || rc == NGX_HTTP_... */
1126 1136
1137 if (rc == NGX_HTTP_UNAUTHORIZED) {
1138 return ngx_http_core_auth_delay(r);
1139 }
1140
1127 ngx_http_finalize_request(r, rc); 1141 ngx_http_finalize_request(r, rc);
1128 return NGX_OK; 1142 return NGX_OK;
1129 } 1143 }
1130 1144
1131 1145
1139 "post access phase: %ui", r->phase_handler); 1153 "post access phase: %ui", r->phase_handler);
1140 1154
1141 access_code = r->access_code; 1155 access_code = r->access_code;
1142 1156
1143 if (access_code) { 1157 if (access_code) {
1158 r->access_code = 0;
1159
1144 if (access_code == NGX_HTTP_FORBIDDEN) { 1160 if (access_code == NGX_HTTP_FORBIDDEN) {
1145 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1161 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1146 "access forbidden by rule"); 1162 "access forbidden by rule");
1147 } 1163 }
1148 1164
1149 r->access_code = 0; 1165 if (access_code == NGX_HTTP_UNAUTHORIZED) {
1166 return ngx_http_core_auth_delay(r);
1167 }
1168
1150 ngx_http_finalize_request(r, access_code); 1169 ngx_http_finalize_request(r, access_code);
1151 return NGX_OK; 1170 return NGX_OK;
1152 } 1171 }
1153 1172
1154 r->phase_handler++; 1173 r->phase_handler++;
1155 return NGX_AGAIN; 1174 return NGX_AGAIN;
1175 }
1176
1177
1178 static ngx_int_t
1179 ngx_http_core_auth_delay(ngx_http_request_t *r)
1180 {
1181 ngx_http_core_loc_conf_t *clcf;
1182
1183 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1184
1185 if (clcf->auth_delay == 0) {
1186 ngx_http_finalize_request(r, NGX_HTTP_UNAUTHORIZED);
1187 return NGX_OK;
1188 }
1189
1190 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1191 "delaying unauthorized request");
1192
1193 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
1194 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1195 }
1196
1197 r->read_event_handler = ngx_http_test_reading;
1198 r->write_event_handler = ngx_http_core_auth_delay_handler;
1199
1200 r->connection->write->delayed = 1;
1201 ngx_add_timer(r->connection->write, clcf->auth_delay);
1202
1203 /*
1204 * trigger an additional event loop iteration
1205 * to ensure constant-time processing
1206 */
1207
1208 ngx_post_event(r->connection->write, &ngx_posted_next_events);
1209
1210 return NGX_OK;
1211 }
1212
1213
1214 static void
1215 ngx_http_core_auth_delay_handler(ngx_http_request_t *r)
1216 {
1217 ngx_event_t *wev;
1218
1219 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1220 "auth delay handler");
1221
1222 wev = r->connection->write;
1223
1224 if (wev->delayed) {
1225
1226 if (ngx_handle_write_event(wev, 0) != NGX_OK) {
1227 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1228 }
1229
1230 return;
1231 }
1232
1233 ngx_http_finalize_request(r, NGX_HTTP_UNAUTHORIZED);
1156 } 1234 }
1157 1235
1158 1236
1159 ngx_int_t 1237 ngx_int_t
1160 ngx_http_core_content_phase(ngx_http_request_t *r, 1238 ngx_http_core_content_phase(ngx_http_request_t *r,
3392 3470
3393 clcf->client_max_body_size = NGX_CONF_UNSET; 3471 clcf->client_max_body_size = NGX_CONF_UNSET;
3394 clcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE; 3472 clcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
3395 clcf->client_body_timeout = NGX_CONF_UNSET_MSEC; 3473 clcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
3396 clcf->satisfy = NGX_CONF_UNSET_UINT; 3474 clcf->satisfy = NGX_CONF_UNSET_UINT;
3475 clcf->auth_delay = NGX_CONF_UNSET_MSEC;
3397 clcf->if_modified_since = NGX_CONF_UNSET_UINT; 3476 clcf->if_modified_since = NGX_CONF_UNSET_UINT;
3398 clcf->max_ranges = NGX_CONF_UNSET_UINT; 3477 clcf->max_ranges = NGX_CONF_UNSET_UINT;
3399 clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT; 3478 clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
3400 clcf->client_body_in_single_buffer = NGX_CONF_UNSET; 3479 clcf->client_body_in_single_buffer = NGX_CONF_UNSET;
3401 clcf->internal = NGX_CONF_UNSET; 3480 clcf->internal = NGX_CONF_UNSET;
3607 prev->keepalive_disable, 3686 prev->keepalive_disable,
3608 (NGX_CONF_BITMASK_SET 3687 (NGX_CONF_BITMASK_SET
3609 |NGX_HTTP_KEEPALIVE_DISABLE_MSIE6)); 3688 |NGX_HTTP_KEEPALIVE_DISABLE_MSIE6));
3610 ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy, 3689 ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy,
3611 NGX_HTTP_SATISFY_ALL); 3690 NGX_HTTP_SATISFY_ALL);
3691 ngx_conf_merge_msec_value(conf->auth_delay, prev->auth_delay, 0);
3612 ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since, 3692 ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
3613 NGX_HTTP_IMS_EXACT); 3693 NGX_HTTP_IMS_EXACT);
3614 ngx_conf_merge_uint_value(conf->max_ranges, prev->max_ranges, 3694 ngx_conf_merge_uint_value(conf->max_ranges, prev->max_ranges,
3615 NGX_MAX_INT32_VALUE); 3695 NGX_MAX_INT32_VALUE);
3616 ngx_conf_merge_uint_value(conf->client_body_in_file_only, 3696 ngx_conf_merge_uint_value(conf->client_body_in_file_only,