# Redirect based on php-set cookies

**URL:** <https://www.ruby-forum.com/t/redirect-based-on-php-set-cookies/183712>\
**Category:** NGINX\
**Created:** [February 18, 2010, 11:05pm UTC](https://www.ruby-forum.com/t/redirect-based-on-php-set-cookies/183712 "2010-02-18T23:05:20Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![tqvn2004](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/8dc957/32.png) [@tqvn2004](https://www.ruby-forum.com/u/tqvn2004)\
**Post date:** [February 18, 2010, 11:05pm UTC](https://www.ruby-forum.com/t/redirect-based-on-php-set-cookies/183712/1 "2010-02-18T23:05:20Z")

</div>

Hi guys,

I am planning to use nginx as reserve proxy in front my Apache server.  
Our site is under heavy DoS attack, where attacker sends a lot of  
malformed HTTP request to flood Apache. I intend to filter out the  
attacker by:

- Setting up nginx as reserve proxy

- If user connect for the first time, redirect to a test.php page, where  
a captcha is used to detect if it is really human.

- If pass, a secret cookie is set to identify this user for a period of  
time. With this cookie, user will be able to go further into Apache.

As a result, I need to have some kind of rewrite rule based on checking  
cookie value (this is calculated by sha1 REMOTE\_ADDR + REQUEST\_DATE, for  
example, for each user). Could anyone suggest a easy way of implementing  
this with nginx?

Thanks!

Posted at Nginx Forum:

> **[Redirect based on php-set cookies](https://forum.nginx.org/read.php?2,55378,55378#msg-55378)**
>
> Hi guys, I am planning to use nginx as reserve proxy in front my Apache server. Our site is under heavy DoS attack, where attacker sends a lot of malformed HTTP request to flood Apache. I intend to filter out the attacker by: - Setting up nginx as...

---

<div class="post-metadata">

**Author:** ![tqvn2004](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/8dc957/32.png) [@tqvn2004](https://www.ruby-forum.com/u/tqvn2004)\
**Post date:** [February 22, 2010, 10:12pm UTC](https://www.ruby-forum.com/t/redirect-based-on-php-set-cookies/183712/2 "2010-02-22T22:12:52Z")

</div>

Hi,

I am writing a module to do the above-mentioned task. I need to access  
system date, or the date of the request (for example  
$\_SERVER[‘REQUEST\_TIME’] in PHP) to put into security session; but I  
could not find this variable in Nginx 7.x. Exists such variable in  
Nginx, or I have to get the value from external library?

Thanks in advance!

Posted at Nginx Forum:

> **[Re: Redirect based on php-set cookies](https://forum.nginx.org/read.php?2,55378,56264#msg-56264)**
>
> Hi guys, I am planning to use nginx as reserve proxy in front my Apache server. Our site is under heavy DoS attack, where attacker sends a lot of malformed HTTP request to flood Apache. I intend to filter out the attacker by: - Setting up nginx as...

---

<div class="post-metadata">

**Author:** ![tqvn2004](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/8dc957/32.png) [@tqvn2004](https://www.ruby-forum.com/u/tqvn2004)\
**Post date:** [February 10, 2011, 1:43pm UTC](https://www.ruby-forum.com/t/redirect-based-on-php-set-cookies/183712/3 "2011-02-10T13:43:40Z")

</div>

To use the new version of secret\_cookie module

In the nginx’s config, you can use the following directives:

- secret\_cookie [on/off] : Turn on or turn off the module functionality

Note: If the module is turned off, all cookie check will return true.

- secret\_cookie\_def on/off name=NAME rule=RULE duration=DURATION  
salt=SALT ua\_limit=UA\_LIMIT log=on/off

This directive define one secret\_cookie check (you can define more than  
one as required). You can set individual secret\_cookie check to on or  
off separately. Other settings are:

- NAME: Name of the cookie of interest.

- RULE: If a cookie with such a name existed in HTTP header,  
secret\_cookie module will check it again this rule. The rule is: t =  
time to live, s=salt value, u=user agent, a=remote IP address. For  
example, rule=usat will check if the content of the cookie of interest  
is the sha value of user agent + salt value + remote IP address + time  
to live. You can repeat the rule if required (for example, rule=susast  
will add salt repeatedly for several place)

- DURATION: The time for the cookie to live. If the cookie is valid for  
1 hour, then duration=3600. The duration check is only meaningful if  
rule contains “time to live”.

- SALT: A random string to increase the secure of secret cookie. Only  
meaningful if the rule contains salt.

- UA\_LIMIT: Sometime the user agent can be very long, which will cause  
problem for secret\_cookie check (more processing time, more memory etc).  
You can limit the check to only first few byte of the user agent. For  
example, ua\_limit=25 means checking only first 25 bytes.

- log=on/off: Turn on or off the logging of secret\_cookie checking.

One example config with secret\_cookie module enable:

```auto
# Turn secret_cookie module on
secret_cookie on;
# Duration: 1 day = 86400, 2 day = 172800, 3 day = 259200, 1 weeks =
604800
# Define AntiDoS cookie
secret_cookie_def on name=AntiDoS rule=sutas duration=86400
salt=2j3ns3a ua_limit=10 log=off;
# Define RestrictedArea cooke
secret_cookie_def on name=RestrictedArea rule=tsau duration=7200
salt=3nh3323 us_limit=20 log=on;

# If AntiDoS cookie is not set, redirect to verification page
if ($secret_cookie_value !~ (AntiDoS)) {
     rewrite ^(.*)$ /verification/index.php;
}

location ~* /verification/.*\.php$ {
   # This is the verification location, where you should setup a php
captcha for user/bot identification.
   # If captcha is valid, assign user an AntiDoS cookie which match the
above rule.
}

# These are protected areas, only Admin can enter
location ~* ^/(admin|forum/admincp)/ {
    # If RestrictedArea cookie is not set, then redirect to admin
verification page
    if ($secret_cookie_value !~ (RestrictedArea)){
         rewrite ^(.*)$ /admin_verification/index.php last;
    }
}

location ~* /admin_verification/.*\.php$ {
   # Again, this is verification location, where you should setup a php
captcha for admin identification.
   # If captcha is valid, assign admin an RestrictedArea cookie which
match the above rule.
}

```

Posted at Nginx Forum:

> **[Re: Redirect based on php-set cookies](https://forum.nginx.org/read.php?2,55378,173804#msg-173804)**
>
> Hi guys, I am planning to use nginx as reserve proxy in front my Apache server. Our site is under heavy DoS attack, where attacker sends a lot of malformed HTTP request to flood Apache. I intend to filter out the attacker by: - Setting up nginx as...

---

<div class="post-metadata">

**Author:** ![tqvn2004](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/8dc957/32.png) [@tqvn2004](https://www.ruby-forum.com/u/tqvn2004)\
**Post date:** [February 24, 2010, 3:07pm UTC](https://www.ruby-forum.com/t/redirect-based-on-php-set-cookies/183712/4 "2010-02-24T15:07:20Z")

</div>

Not sure if anyone interested in this module, but here is the code I  
made:

/\*

- Author: tqvn2004
- Date: 24/02/2010  
\*/

#include  
#include  
#include  
#include

/\*

- The module set the $secret\_cookie variable
- to “true” if a secret cookie is set at client.
- Based on the variable, user can be classified
- into verified and non-verified one.  
\*/

#define NGX\_HTTP\_SECRET\_COOKIE\_OFF 0 // Default state  
#define NGX\_HTTP\_SECRET\_COOKIE\_ON 1

#define NGX\_HTTP\_SECRET\_COOKIE\_NOT\_SET 1  
#define NGX\_HTTP\_SECRET\_COOKIE\_SET 0

#define NGX\_HTTP\_SECRET\_COOKIE\_DEFAULT\_VALID\_PERIOD 604800 // 7 days  
#define NGX\_HTTP\_SECRET\_COOKIE\_MIN\_VALID\_PERIOD 3600 // 1 hour

// Default rule: Salt + Remote-address + User-agent + Time + Salt  
#define NGX\_HTTP\_SECRET\_COOKIE\_DEFAULT\_RULE “sauts”  
#define NGX\_HTTP\_SECRET\_COOKIE\_DEFAULT\_SALT “x83n7h32”  
#define NGX\_HTTP\_SECRET\_COOKIE\_DEFAULT\_NAME “secret\_cookie”

// Record for Location configuration  
typedef struct {  
ngx\_flag\_t enable;  
ngx\_str\_t name;  
ngx\_str\_t rule;  
ngx\_str\_t salt;  
ngx\_uint\_t validperiod;

} ngx\_http\_secret\_cookie\_conf\_t;

// Return variable structure  
typedef struct {  
ngx\_str\_t name;  
ngx\_http\_get\_variable\_pt handler;  
uintptr\_t data;  
} ngx\_http\_secret\_cookie\_variable\_t;

// Context variable: This alive for request’s duration  
typedef struct {  
ngx\_uint\_t secret\_cookie\_status;  
ngx\_str\_t secret\_cookie;  
} ngx\_http\_secret\_cookie\_ctx\_t;

static void \*ngx\_http\_secret\_cookie\_create\_conf(ngx\_conf\_t \*cf);  
static char \*ngx\_http\_secret\_cookie\_merge\_conf(ngx\_conf\_t \*cf, void  
\*parent,  
void \*child);  
static ngx\_int\_t ngx\_http\_secret\_cookie\_add\_variable(ngx\_conf\_t \*cf);  
static ngx\_int\_t ngx\_http\_secret\_cookie\_variable(ngx\_http\_request\_t \*r,  
ngx\_http\_variable\_value\_t \*v, uintptr\_t data);  
static ngx\_http\_secret\_cookie\_ctx\_t \*  
ngx\_http\_secret\_cookie(ngx\_http\_request\_t \*r,  
ngx\_http\_secret\_cookie\_conf\_t \*cf);  
static char \* ngx\_http\_secret\_cookie\_valid\_period(ngx\_conf\_t \*cf, void  
\*post,  
void \*data);  
static char \* ngx\_http\_secret\_cookie\_name(ngx\_conf\_t \*cf, void \*post,  
void \*data);  
static char \* ngx\_http\_secret\_cookie\_rule(ngx\_conf\_t \*cf, void \*post,  
void \*data);  
static u\_char \* ngx\_num2str(u\_char \*buf, u\_char \*last, uint64\_t ui64);  
static ngx\_int\_t ngx\_raw\_vs\_hex(u\_char \*rawbuf, size\_t rlen, u\_char  
\*hexbuf, size\_t hlen);

// A pointer to post-handler function to validate the “validperiod”  
param  
static ngx\_conf\_post\_handler\_pt ngx\_http\_secret\_cookie\_valid\_period\_p =  
ngx\_http\_secret\_cookie\_valid\_period;  
static ngx\_conf\_post\_handler\_pt ngx\_http\_secret\_cookie\_name\_p =  
ngx\_http\_secret\_cookie\_name;  
static ngx\_conf\_post\_handler\_pt ngx\_http\_secret\_cookie\_rule\_p =  
ngx\_http\_secret\_cookie\_rule;

static ngx\_command\_t ngx\_http\_secret\_cookie\_commands[] = {  
/\* Define secret\_cookie directive (on or off).  
\* Location: Main, HTTP, Location  
\* Take: 1 parameter, a Flag  
\*/  
{ ngx\_string(“secret\_cookie”),  
NGX\_HTTP\_MAIN\_CONF|NGX\_HTTP\_SRV\_CONF|NGX\_HTTP\_LOC\_CONF|NGX\_CONF\_TAKE1,  
ngx\_conf\_set\_flag\_slot, // Convert on/off to value  
NGX\_HTTP\_LOC\_CONF\_OFFSET, // Instruct value to be written to  
Location Config,  
offsetof(ngx\_http\_secret\_cookie\_conf\_t, enable), // with this  
offset  
NULL }, // No post-handler is necessary.

```
/* Define secret_cookie_var1 directive
 * Location: Main, HTTP, Location
 * Taking: 1 parameter, a string
 */
{ ngx_string("secret_cookie_rule"),
  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  ngx_conf_set_str_slot,
  NGX_HTTP_LOC_CONF_OFFSET,
  offsetof(ngx_http_secret_cookie_conf_t, rule),
  &ngx_http_secret_cookie_rule_p },

{ ngx_string("secret_cookie_salt"),
  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  ngx_conf_set_str_slot,
  NGX_HTTP_LOC_CONF_OFFSET,
  offsetof(ngx_http_secret_cookie_conf_t, salt),
  NULL },

{ ngx_string("secret_cookie_name"),
  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  ngx_conf_set_str_slot,
  NGX_HTTP_LOC_CONF_OFFSET,
  offsetof(ngx_http_secret_cookie_conf_t, name),
  &ngx_http_secret_cookie_name_p },

{ ngx_string("secret_cookie_valid_period"),
  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  ngx_conf_set_num_slot,
  NGX_HTTP_LOC_CONF_OFFSET,
  offsetof(ngx_http_secret_cookie_conf_t, validperiod),
  &ngx_http_secret_cookie_valid_period_p }, // Post-handler function

  ngx_null_command

```

};

static ngx\_http\_module\_t ngx\_http\_secret\_cookie\_module\_ctx = {  
ngx\_http\_secret\_cookie\_add\_variable, /\* preconfiguration _/  
NULL, /_ postconfiguration \*/

```
NULL, /* create main configuration 

```

_/  
NULL, /_ init main configuration \*/

```
NULL, /* create server configuration 

```

_/  
NULL, /_ merge server configuration  
\*/

```
ngx_http_secret_cookie_create_conf, /* create location 

```

configuration _/  
ngx\_http\_secret\_cookie\_merge\_conf /_ merge location  
configuration \*/  
};

ngx\_module\_t ngx\_http\_secret\_cookie\_module = {  
NGX\_MODULE\_V1,  
&ngx\_http\_secret\_cookie\_module\_ctx, /\* module context _/  
ngx\_http\_secret\_cookie\_commands, /_ module directives _/  
NGX\_HTTP\_MODULE, /_ module type _/  
NULL, /_ init master _/  
NULL, /_ init module _/  
NULL, /_ init process _/  
NULL, /_ init thread _/  
NULL, /_ exit thread _/  
NULL, /_ exit process _/  
NULL, /_ exit master \*/  
NGX\_MODULE\_V1\_PADDING  
};

static ngx\_http\_secret\_cookie\_variable\_t ngx\_http\_secret\_cookie\_vars[]  
= {  
{ ngx\_string(“secret\_cookie\_not\_set”),  
ngx\_http\_secret\_cookie\_variable,  
NGX\_HTTP\_SECRET\_COOKIE\_NOT\_SET },  
{ ngx\_null\_string, NULL, 0 }  
};

/\*

- This function set the $secret\_cookie to 1, if the

- cookie is set and valid.  
\*/  
static ngx\_int\_t  
ngx\_http\_secret\_cookie\_variable(ngx\_http\_request\_t \*r,  
ngx\_http\_variable\_value\_t \*v,  
uintptr\_t data)  
{  
ngx\_http\_secret\_cookie\_ctx\_t \*rctx;  
ngx\_http\_secret\_cookie\_conf\_t \*cf;

{  
\*v = ngx\_http\_variable\_null\_value;  
return NGX\_OK;  
}  
}  
// Always return true (i.e. secret\_cookie not set),  
// unless module is enalbed and secret\_cookie is checked…  
\*v = ngx\_http\_variable\_true\_value;  
return NGX\_OK;  
}

/\*

- This is the main function: It looks for a secret cookie

- in the HTTP request header, and compared with constructed value

- Return: Secret Cookie SET or NOT SET!  
\*/  
static ngx\_http\_secret\_cookie\_ctx\_t \*  
ngx\_http\_secret\_cookie(ngx\_http\_request\_t \*r,  
ngx\_http\_secret\_cookie\_conf\_t \*cf)  
{  
ngx\_int\_t n, alen, tlen, slen, ulen, total\_len;  
ngx\_http\_secret\_cookie\_ctx\_t \*ctx;  
time\_t timestamp; // Current UNIX timestamp  
u\_char \*user\_agent = NULL, \*salt = NULL,  
\*remote\_addr = NULL, \*last\_change = NULL;  
u\_char \*secret\_cookie;  
u\_char \*p;  
ngx\_sha1\_t sha\_ctx;  
#if (NGX\_DEBUG)  
// A string for print debug info  
ngx\_str\_t mypen;

- "%V"", ulen, &mypen);  
#endif  
}  
total\_len += ulen;  
default:  
// Do not copy char  
break;  
}  
n++;  
}

/\* Add $secret\_cookie\_set variable to the http process.

- Called by “preconfiguration” hook!  
\*/  
static ngx\_int\_t  
ngx\_http\_secret\_cookie\_add\_variable(ngx\_conf\_t \*cf)  
{  
ngx\_http\_secret\_cookie\_variable\_t \*var;  
ngx\_http\_variable\_t \*v;

NGX\_HTTP\_VAR\_CHANGEABLE);  
if (v == NULL) {  
return NGX\_ERROR;  
}

```
    v->get_handler = var->handler;
    v->data = var->data;
}

return NGX_OK;

```

}

/\*

- This function is called when location configuration is created.

- It will create a default configuration for secret\_cookie module.  
\*/  
static void \*  
ngx\_http\_secret\_cookie\_create\_conf(ngx\_conf\_t \*cf)  
{  
ngx\_http\_secret\_cookie\_conf\_t \*conf;

/\*

- This function is called when location configuration is merged to main  
config.

- It will create a default configuration for secret\_cookie module.  
\*/  
static char \*  
ngx\_http\_secret\_cookie\_merge\_conf(ngx\_conf\_t \*cf, void \*parent, void  
\*child)  
{  
ngx\_http\_secret\_cookie\_conf\_t \*prev = parent;  
ngx\_http\_secret\_cookie\_conf\_t \*conf = child;

/\*

- This function is called after secret\_cookie\_valid\_period is passed

- from config to module. Here you can validate the param, or change the

- param to meaningful value.  
\*/  
static char \*  
ngx\_http\_secret\_cookie\_valid\_period(ngx\_conf\_t \*cf, void \*post, void  
\*data)  
{  
ngx\_uint\_t \*validperiod = data;

/\*

- This function is called after secret\_cookie\_name is passed from  
config

- to module. Here you can validate the param, or change the

- param to meaningful value.  
\*/  
static char \*  
ngx\_http\_secret\_cookie\_name(ngx\_conf\_t \*cf, void \*post, void \*data)  
{  
ngx\_str\_t \*name = data;

/\*

- This function is called after secret\_cookie\_rule is passed from  
config

- to module. Here you can validate the param, or change the

- param to meaningful value.  
\*/  
static char \*  
ngx\_http\_secret\_cookie\_rule(ngx\_conf\_t \*cf, void \*post, void \*data)  
{  
ngx\_str\_t \*rule = data;  
u\_char \*new;  
size\_t i, len;

- Convert an int64 to string presentation  
\*/  
static u\_char \* ngx\_num2str(u\_char \*buf, u\_char \*last, uint64\_t ui64)  
{  
u\_char _p, temp;  
/_  
\* we need temp only,  
\* but icc issues the warning  
\*/  
size\_t len;  
uint32\_t ui32;

/\*

- Comparison of a raw string and a hex-style string  
\*/  
static ngx\_int\_t ngx\_raw\_vs\_hex(u\_char _rawbuf, size\_t rlen, u\_char  
 hexbuf, size\_t hlen)  
{  
static u\_char hex[] = “0123456789abcdef”;  
u\_char hexchar[] = “aa”;  
ngx\_int\_t len, i;  
// Compare by the shortest length  
len = ((rlen \< hlen / 2) ? rlen : hlen / 2);  
i = 0;  
while (i \< len){  
// Calculate a hexchar from rawbuff  
hexchar[1] = hex & 0xf];  
hexchar[0] = hex[(rawbuf\>\>4) & 0xf];  
if ((hexchar[0] != hexbuf[2i]) || (hexchar[1] !=  
hexbuf[2_i+1])){  
return 1;  
}  
i++;  
}  
return 0;  
}

Posted at Nginx Forum:

> **[Re: Redirect based on php-set cookies](https://forum.nginx.org/read.php?2,55378,56822#msg-56822)**
>
> Hi guys, I am planning to use nginx as reserve proxy in front my Apache server. Our site is under heavy DoS attack, where attacker sends a lot of malformed HTTP request to flood Apache. I intend to filter out the attacker by: - Setting up nginx as...

---

<div class="post-metadata">

**Author:** ![tqvn2004](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/8dc957/32.png) [@tqvn2004](https://www.ruby-forum.com/u/tqvn2004)\
**Post date:** [December 10, 2011, 5:22pm UTC](https://www.ruby-forum.com/t/redirect-based-on-php-set-cookies/183712/5 "2011-12-10T17:22:18Z")

</div>

I Became an error can i contact you ?

Posted at Nginx Forum:

> **[Re: Redirect based on php-set cookies](https://forum.nginx.org/read.php?2,55378,219859#msg-219859)**
>
> Hi guys, I am planning to use nginx as reserve proxy in front my Apache server. Our site is under heavy DoS attack, where attacker sends a lot of malformed HTTP request to flood Apache. I intend to filter out the attacker by: - Setting up nginx as...

---

<div class="post-metadata">

**Author:** ![tqvn2004](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/8dc957/32.png) [@tqvn2004](https://www.ruby-forum.com/u/tqvn2004)\
**Post date:** [September 21, 2010, 10:06pm UTC](https://www.ruby-forum.com/t/redirect-based-on-php-set-cookies/183712/6 "2010-09-21T22:06:00Z")

</div>

Thank to nginx, our server was able to mitigate the Slowloris DoS  
attack, which killed Apache with partial or malformed HTTP headers. The  
above mentioned secret\_cookie module helped to filter out all other  
valid botnet requests with this config:

[code]## If secret\_cookie not set, redirect to verification page  
if ($secret\_cookie\_not\_set) {  
#store the old uri  
set $uri\_old $uri$is\_args$args;  
rewrite ^(.\*)$ /verification/index.php;  
}

## Verification page: a php code that check for user response (for

example recaptcha),

## and setting the secret\_cookie if response is valid

location ~\* /verification/.\*.php$ {  
# Do not allow direct access  
internal;  
# If IP in the white list,  
# return without the checking process  
if ($whitelist ~ ^bot) {  
rewrite ^ $uri\_old last;  
}  
# Turn off the proxy’s cache  
proxy\_cache off;

```
# Turn off access log, but turn on error log
access_log off;
error_log /usr/local/nginx-proxy3/logs/verification.log error;

# Set the rate limite for verification page
limit_req zone=vzone burst=15 nodelay;
# Also set the connection limit for verification page
limit_conn gulag 5;
include /usr/local/nginx-proxy3/conf/fastcgi.conf;
fastcgi_pass 127.0.0.1:9002;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME

```

/home/tqvn2004/public\_html$fastcgi\_script\_name;  
fastcgi\_param URI\_OLD $uri\_old;  
}[/code]

And here is an example index.php code for user verification:

[code]\<?php  
$x = rand(1,15);  
$y = rand(1,15);

## Secret cookie setting, must match one define in nginx.conf

$secret\_cookie\_salt = “aDt%&sa”;  
$secret\_cookie\_valid\_period = 86400;  
$secret\_cookie\_name = “secret\_cookie”;  
$errormsg = “”;  
$result\_cookie\_name = “verify\_human”;  
$uri\_cookie\_name = “reference\_uri”;  
$verification\_uri = ‘/verification/index.php’;  
$test\_uri = ‘/verification/’;  
$domain = “.example.org”;  
setcookie($result\_cookie\_name,  
sha1($secret\_cookie\_salt . strval($x+$y) .  
$secret\_cookie\_salt),  
time() + 600,  
‘/verification’, // Only available in ‘verification’ folder  
$domain, FALSE, TRUE);  
if (isset($\_SERVER[‘URI\_OLD’]) && (strpos($\_SERVER[‘URI\_OLD’],  
$test\_uri) !== 0)){  
setcookie($uri\_cookie\_name,  
$\_SERVER[‘URI\_OLD’],  
time() + 600,  
‘/verification’, // Only available in 'verification  
folder  
$domain, FALSE, TRUE);  
}

if (isset($\_GET) && isset($\_GET[‘result’])) {  
if (isset($\_COOKIE) && isset($\_COOKIE[$result\_cookie\_name])){  
if (sha1($secret\_cookie\_salt . $\_GET[‘result’] .  
$secret\_cookie\_salt)  
== $\_COOKIE[$result\_cookie\_name]){  
// Set the secret cookie and redirect  
setcookie($secret\_cookie\_name,  
sha1($secret\_cookie\_salt .

floor($\_SERVER[‘REQUEST\_TIME’]/$secret\_cookie\_valid\_period) .  
$\_SERVER[‘REMOTE\_ADDR’] .  
$\_SERVER[‘HTTP\_USER\_AGENT’] .  
$secret\_cookie\_salt),  
time()+$secret\_cookie\_valid\_period,  
‘/’,  
$domain, FALSE, TRUE);  
//$http = (isset($\_SERVER[‘HTTPS’]) ? ‘https://’ :  
‘http://’);  
//$port = ($\_SERVER[‘SERVER\_PORT’] == 80 ? ‘’ :  
‘:’.$\_SERVER[‘SERVER\_PORT’]);  
$http = ($\_SERVER[‘SERVER\_PORT’] == 443 ? ‘https://’ :  
‘http://’);  
$uri = (!isset($\_COOKIE[$uri\_cookie\_name]) ? ‘/’ :  
$\_COOKIE[$uri\_cookie\_name]);  
// Redirect to new location  
header("Location: " . $http . $\_SERVER[‘HTTP\_HOST’] .  
$uri);  
} else {  
$errormsg = “The result is not correct, try again!!!”;

```
    }

```

} else {  
$errormsg = “Cannot verify your result. Try again!! You should  
also check if: (1) your browser does accept cookies, (2) your proxy, if  
any, does accept cookies…”;  
}  
}

echo '

body {  
background-color: #999999;  
font-size:13px;  
font-family: Verdana, Arial, Helvetica, sans-serif;  
}  
div#outer {  
width: 60%;  
background-color:#FFFFFF;  
margin-top: 50px;  
margin-bottom: 50px;  
margin-left: auto;  
margin-right: auto;  
padding: 0px;  
border: thin solid #000000;  
}  
div#header {  
padding: 15px;  
margin: 0px;  
text-align: center;  
color: #999999;  
}  
div#main {  
margin-top: 0px;  
margin-bottom: 20px;  
padding: 10px;  
text-align: center;  
font-size: 15px;  
}  
div#main\_header {  
padding-bottom: 15px;  
}  
div#main\_error {  
padding-top: 15px;  
color: red;  
}  
#formula{  
font-weight:bold;  
font-size: 20px;  
}  
div#footer {  
padding: 15px;  
margin: 0px;  
border-top: thin solid #000000;  
text-align: center;  
}

> **[Example Domain](http://example.org)**

```
    Example.org

  Perform the math question:' .
  '
      '. $x .' + '. $y .' =
  '.$errormsg.'
  ' .
'

    Our server is under heavy DoS attack, this verification page

```

helps us identify you as human.

';  
?\>  
[/code]

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,55378,132704#msg-132704](http://forum.nginx.org/read.php?2,55378,132704#msg-132704)

---

<div class="post-metadata">

**Author:** ![tqvn2004](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/8dc957/32.png) [@tqvn2004](https://www.ruby-forum.com/u/tqvn2004)\
**Post date:** [February 10, 2011, 1:12pm UTC](https://www.ruby-forum.com/t/redirect-based-on-php-set-cookies/183712/7 "2011-02-10T13:12:54Z")

</div>

For someone who is interested in using this module

To compile with nginx, do the following steps:

1. Download Nginx source code from [http://wiki.nginx.org/NginxInstall](http://wiki.nginx.org/NginxInstall),  
and put them in, let’s say, folder ‘nginx’

2. Install OpenSSL for your Linux.

3. You need also to download OpenSSL source code, and copy folder  
openssl/crypto/sha to nginx/src. This step is important, as the  
secret\_cookie module depends on OpenSSL at compile time.

4. Copy sha/sha.h in openssl/crypto/sha into nginx/src/core. You will  
get compilation error if not doing this.

5. Now create a folder name nginx/src/secret\_cookie to store the  
secret\_cookie module. Put the config and ngx\_http\_secret\_cookie\_module.c  
(described below) in this folder.

6. Go to folder nginx and now you can configure the make:

./configure --prefix=/usr/local/nginx-proxy/ --with-http\_ssl\_module  
–add-module=src/secret\_cookie --with-sha1=src/sha

Please change the directory as per your server configuration.

1. Run make, if everything is ok, you should now be able to compile  
nginx with the secret\_cookie module.

Content of the config file:

`ngx_addon_name=ngx_http_secret_cookie_module
HTTP_MODULES="$HTTP_MODULES ngx_http_secret_cookie_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS
$ngx_addon_dir/ngx_http_secret_cookie_module.c"
`

Content of the ngx\_http\_secret\_cookie\_module.c file:

```auto
/*
 * Copyright (C) Huan Cong Nguyen
 * Version 1.0.6
 */

#include
#include
#include
#include

/*
 * This module set the $secret_cookie_value variable
 * to the names of valid secret cookies set at client.
 * Based on the variable, user can be classified
 * into verified and non-verified one.
 */
#define NGX_HTTP_SECRET_COOKIE_OFF 0 // Default state
#define NGX_HTTP_SECRET_COOKIE_ON 1

#define NGX_HTTP_SECRET_COOKIE_NOT_SET 0

#define NGX_HTTP_SECRET_COOKIE_MINIMUM_DURATION 600 // 10
minutes
#define NGX_HTTP_SECRET_COOKIE_MINIMUM_UA_LIMIT 10 // 10
characters
#define NGX_HTTP_SECRET_COOKIE_MAX_SHORT_STR_SIZE 12 // Allow only
12 characters in name, salt and rule

// Rule elements
#define NGX_HTTP_SECRET_COOKIE_RULE_SALT 's'
#define NGX_HTTP_SECRET_COOKIE_RULE_ADDRESS 'a'
#define NGX_HTTP_SECRET_COOKIE_RULE_TIME 't'
#define NGX_HTTP_SECRET_COOKIE_RULE_USER_AGENT 'u'
#define NGX_HTTP_SECRET_COOKIE_DIVIDER ' '

// Record for each secret cookie
typedef struct {
    ngx_flag_t status;
    ngx_flag_t log;
    ngx_uint_t duration;
    ngx_str_t name;
    ngx_str_t rule;
    ngx_str_t salt;
    ngx_uint_t ua_limit;
} ngx_http_secret_cookie_t;

// Record for Location configuration
typedef struct {
    ngx_flag_t status;
    ngx_array_t *secret_cookies;
    ngx_http_variable_value_t *secret_cookie_value_disabled;
} ngx_http_secret_cookie_conf_t;

// Context variable: This alive for request's duration
typedef struct {
    ngx_http_variable_value_t *secret_cookie_value;
} ngx_http_secret_cookie_ctx_t;

// Return variable structure
typedef struct {
    ngx_str_t name;
    ngx_http_get_variable_pt handler;
    uintptr_t data;
} ngx_http_secret_cookie_variable_t;

static void *ngx_http_secret_cookie_create_conf(ngx_conf_t *cf);
static char *ngx_http_secret_cookie_merge_conf(ngx_conf_t *cf, void
*parent,
    void *child);
static ngx_int_t ngx_http_secret_cookie_add_variable(ngx_conf_t *cf);
static ngx_int_t ngx_http_secret_cookie_variable(ngx_http_request_t *r,
    ngx_http_variable_value_t *v, uintptr_t data);
static ngx_http_secret_cookie_ctx_t *
ngx_http_secret_cookie_handler(ngx_http_request_t *r,
    ngx_http_secret_cookie_conf_t *cf);
static char *ngx_http_secret_cookie_def(ngx_conf_t *cf, ngx_command_t
*cmd, void *conf);
static u_char * ngx_num2str(u_char *buf, u_char *last, uint64_t ui64);
static ngx_int_t ngx_raw_vs_hex(u_char *rawbuf, size_t rlen, u_char
*hexbuf, size_t hlen);

static ngx_command_t ngx_http_secret_cookie_commands[] = {
    /* Define secret_cookie directive (on or off).
     * Location: Main, HTTP
     * Take: 1 parameter, a Flag
     */
    { ngx_string("secret_cookie"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_flag_slot, // Convert on/off to value
      NGX_HTTP_LOC_CONF_OFFSET, // Instruct value to be written to
Location Config,
      offsetof(ngx_http_secret_cookie_conf_t, status), // with this
offset
      NULL }, // No post-handler is necessary.

    /* Define secret_cookie_def directive ([off] name=xyz salt=abc
rule=mnk duration=8323)
     * Location: Main, HTTP
     * Taking: 4 or 5 parameters
     */
    { ngx_string("secret_cookie_def"),

NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE4|NGX_CONF_TAKE5|NGX_CONF_TAKE6|NGX_CONF_TAKE7,
      ngx_http_secret_cookie_def,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

      ngx_null_command
};

static ngx_http_module_t ngx_http_secret_cookie_module_ctx = {
    ngx_http_secret_cookie_add_variable, /* preconfiguration */
    NULL, /* postconfiguration */

    NULL, /* create main configuration
*/
    NULL, /* init main configuration */

    NULL, /* create server configuration
*/
    NULL, /* merge server configuration
*/

    ngx_http_secret_cookie_create_conf, /* create location
configuration */
    ngx_http_secret_cookie_merge_conf /* merge location
configuration */
};

ngx_module_t ngx_http_secret_cookie_module = {
    NGX_MODULE_V1,
    &ngx_http_secret_cookie_module_ctx, /* module context */
    ngx_http_secret_cookie_commands, /* module directives */
    NGX_HTTP_MODULE, /* module type */
    NULL, /* init master */
    NULL, /* init module */
    NULL, /* init process */
    NULL, /* init thread */
    NULL, /* exit thread */
    NULL, /* exit process */
    NULL, /* exit master */
    NGX_MODULE_V1_PADDING
};

static ngx_http_secret_cookie_variable_t ngx_http_secret_cookie_vars[]
= {
    { ngx_string("secret_cookie_value"),
ngx_http_secret_cookie_variable,
            NGX_HTTP_SECRET_COOKIE_NOT_SET },
    { ngx_null_string, NULL, 0 }
};

/*
 * This function set the $secret_cookie_value to found secret_cookie
names,
 * if they are set and valid.
 */
static ngx_int_t
ngx_http_secret_cookie_variable(ngx_http_request_t *r,
                                ngx_http_variable_value_t *v,
                                uintptr_t data)
{
    ngx_http_secret_cookie_ctx_t *rctx;
    ngx_http_secret_cookie_conf_t *cf;

    cf = ngx_http_get_module_loc_conf(r,
ngx_http_secret_cookie_module);
    // Check if the module is enable?
    if (cf->status == NGX_HTTP_SECRET_COOKIE_ON){
        // Only perform cookie search if the module is enable
        rctx = ngx_http_secret_cookie_handler(r, cf);

        if (rctx != NULL){
#if (NGX_DEBUG)
            ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                          "secret_cookie: Rctx is returned with
value");
#endif
            *v = *rctx->secret_cookie_value;
            return NGX_OK;
        } else {
            // There is something wrong with the search for secret
cookies,
            // just return null value to fail all user-defined checks
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "secret_cookie: Rctx is null, which is often
due to lack of memory");
            *v = ngx_http_variable_null_value;
            return NGX_OK;
        }
    }
    // In case the secret_cookie is disabled,
    // all defined secret cookies are assumed to be found,
    // so that user-defined checks are successful
    *v = *cf->secret_cookie_value_disabled;
    return NGX_OK;
}

/*
 * This is the main function: It looks for a secret cookie
 * in the HTTP request header, and compared with constructed value
 * Return: Secret Cookie SET or NOT SET!
 */
static ngx_http_secret_cookie_ctx_t *
ngx_http_secret_cookie_handler(ngx_http_request_t *r,
ngx_http_secret_cookie_conf_t *cf)
{
    ngx_http_secret_cookie_ctx_t *ctx;
    ngx_http_secret_cookie_t *sc;

    ngx_uint_t n, i, ua_len;
    ngx_int_t m;
    ngx_str_t name, rule, salt, last_change,
                                  remote_address, user_agent,
                                  computed_sc, submitted_sc, sc_string,
                                  secret_cookie_value;
    time_t timestamp; // Current UNIX timestamp
    u_char *p;
    ngx_sha1_t sha_ctx;

    // Try to get the context variable
    ctx = ngx_http_get_module_ctx(r, ngx_http_secret_cookie_module);

    // If context existed, secret_cookie was checked before, so stop!
    if (ctx){
#if (NGX_DEBUG)
        ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: Checking was done before,
aborting!");
#endif
        return ctx;
    }
    // Otherwise, start the checking process
    if (ctx == NULL) {
#if (NGX_DEBUG)
        ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: Checking was not done before, start
checking");
#endif
        // This r->pool temporary memory will be destroyed later,
        // after this request is served!
        ctx = ngx_pcalloc(r->pool,
sizeof(ngx_http_secret_cookie_ctx_t));
        if (ctx == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   "secret_cookie: Out of memory for context variable
(ctx)");
            return NULL;
        }
        ngx_http_set_ctx(r, ctx, ngx_http_secret_cookie_module);
    }
    ctx->secret_cookie_value = ngx_palloc(r->pool,
sizeof(ngx_http_variable_value_t));
    if (ctx->secret_cookie_value == NULL){
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "secret_cookie: Out of memory for
ctx->secret_cookie_value variable");
        return NULL;
    }
    *ctx->secret_cookie_value = ngx_http_variable_null_value;

    remote_address.len = r->connection->addr_text.len;
    remote_address.data = r->connection->addr_text.data;
    if (r->headers_in.user_agent == NULL) {
        // The user-agent value is null
        user_agent.len = 0;
        user_agent.data = NULL;
#if (NGX_DEBUG)
        ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: User agent is empty");
#endif
    } else {
        // The user-agent value is not null
        user_agent.len = r->headers_in.user_agent->value.len;
        user_agent.data = r->headers_in.user_agent->value.data;
#if (NGX_DEBUG)
        ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: User agent is not empty");
#endif
    }
    secret_cookie_value.len = 0;
    // Allocate maximum size for this variable
    secret_cookie_value.data = ngx_pcalloc(r->pool,
cf->secret_cookie_value_disabled->len);
    if (secret_cookie_value.data == NULL){
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                     "secret_cookie: Out of memory for
secret_cookie_value string");
        return NULL;
    }

    sc = cf->secret_cookies->elts;
    for (i=0; i < cf->secret_cookies->nelts; i++){
        // Cookie name must be initialized first, in case of jumping to
secret_cookie_found!
        name.len = sc[i].name.len;
        name.data = sc[i].name.data;

        if (sc[i].status == NGX_HTTP_SECRET_COOKIE_OFF){
#if (NGX_DEBUG)
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: checking of cookie \"%V\" is off",
&name);
#endif
            goto secret_cookie_found;
        }

        // First, search for the secret_cookie's name in http header:
        m = ngx_http_parse_multi_header_lines(&r->headers_in.cookies,
&name,
                                          &submitted_sc);
        if (m == NGX_DECLINED) {
#if (NGX_DEBUG)
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: cookie \"%V\" is not found in
header", &name);
#endif
            goto secret_cookie_not_found;
        }

#if (NGX_DEBUG)
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: cookie \"%V\" found in header,
value=%V and length=%i",
                   &name, &submitted_sc, submitted_sc.len);
#endif

        if (submitted_sc.len != 2*SHA_DIGEST_LENGTH) {
#if (NGX_DEBUG)
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: size of cookie \"%V\" is incorrect",
&name);
#endif
            goto secret_cookie_not_found;
        }

        // User Agent can be very large. Limit to a certain size
        // to keep small memory footprint
        if ((sc[i].ua_limit > 0) && (user_agent.len > sc[i].ua_limit))
{
            ua_len = sc[i].ua_limit;
        } else {
            ua_len = user_agent.len;
        }

        salt.len = sc[i].salt.len;
        salt.data = sc[i].salt.data;
        rule.len = sc[i].rule.len;
        rule.data = sc[i].rule.data;
        // Obtain current time in second
        timestamp = ngx_time();
        // Calculate the last_change and convert it to string
        last_change.data = ngx_pcalloc(r->pool, NGX_INT64_LEN);
        if (last_change.data == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                             "secret_cookie: Out of memory for
last_change string");
            return NULL;
        }
        p = ngx_num2str(last_change.data,
                        last_change.data + NGX_INT64_LEN,
                        (uint64_t) timestamp / sc[i].duration);
        last_change.len = p - last_change.data;

#if (NGX_DEBUG)
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: name has length=%i and value=%V",
name.len, &name);
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: salt has length=%i and value=%V",
salt.len, &salt);
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: rule has length=%i and value=%V",
rule.len, &rule);
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: duration = %i", sc[i].duration);
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: last_change = %V", &last_change);
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: remote_address has length=%i and
value=%V",
                   remote_address.len, &remote_address);
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: user-agent has length=%i from
value=%V",
                   ua_len, &user_agent);
#endif

        // Second, compute the secret_cookie according to the rule:
        sc_string.len = 0;
        for (n=0; n < rule.len; n++){
            switch (ngx_tolower(rule.data[n])){
                case NGX_HTTP_SECRET_COOKIE_RULE_ADDRESS:
                    sc_string.len += remote_address.len;
                    break;
                case NGX_HTTP_SECRET_COOKIE_RULE_SALT:
                    sc_string.len += salt.len;
                    break;
                case NGX_HTTP_SECRET_COOKIE_RULE_USER_AGENT:
                    sc_string.len += ua_len;
                    break;
                case NGX_HTTP_SECRET_COOKIE_RULE_TIME:
                    sc_string.len += last_change.len;
                    break;
                default:
#if (NGX_DEBUG)
                    ngx_log_debug(NGX_LOG_DEBUG_HTTP,
r->connection->log, 0,
                       "secret_cookie: Unknown rule");
#endif
                    break;
            } // End of switch
        }

        sc_string.data = ngx_pcalloc(r->pool, sc_string.len);
        if (sc_string.data == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "secret_cookie: Out of memory for sc_string
variable");
            return NULL;
        }
        p = sc_string.data;
        for (n=0; n < rule.len; n++){
            switch (ngx_tolower(rule.data[n])){
                case NGX_HTTP_SECRET_COOKIE_RULE_ADDRESS:
                    // This ngx_copy faster than ngx_cpymem with buffer
< 16 bytes
                    p = ngx_copy(p, remote_address.data,
remote_address.len);
                    break;
                case NGX_HTTP_SECRET_COOKIE_RULE_SALT:
                    p = ngx_copy(p, salt.data, salt.len);
                    break;
                case NGX_HTTP_SECRET_COOKIE_RULE_USER_AGENT:
                    if (ua_len > 0){
                        p = ngx_cpymem(p, user_agent.data, ua_len);
                    }
                    break;
                case NGX_HTTP_SECRET_COOKIE_RULE_TIME:
                    p = ngx_copy(p, last_change.data, last_change.len);
                    break;
                default:
#if (NGX_DEBUG)
                    ngx_log_debug(NGX_LOG_DEBUG_HTTP,
r->connection->log, 0,
                       "secret_cookie: Unknown rule");
#endif
                    break;
            } // End of switch
        }
#if (NGX_DEBUG)
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: String to compute secret_cookie has
length=%i and value=%V",
                   sc_string.len, &sc_string);
#endif

        // Third, perform sha1 on the content
        computed_sc.len = SHA_DIGEST_LENGTH;
        computed_sc.data = ngx_pcalloc(r->pool, SHA_DIGEST_LENGTH);
        if (computed_sc.data == NULL) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "secret_cookie: Out of memory for computed_sc
variable");
            return NULL;
        }
        n = ngx_sha1_init(&sha_ctx);
        if (n == 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "secret_cookie: SHA1 init fails");
            return NULL;
        }
        n = ngx_sha1_update(&sha_ctx, sc_string.data, sc_string.len);
        if (n == 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "secret_cookie: SHA1 update fails");
            return NULL;
        }
        n = ngx_sha1_final(computed_sc.data, &sha_ctx);
        if (n == 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "secret_cookie: SHA1 final fails");
            return NULL;
        }
        // Release the sc_string memory:

#if (NGX_DEBUG)
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "secret_cookie: computed_secret_cookie has length=%i
and value=%V", SHA_DIGEST_LENGTH, &computed_sc);
#endif
        if (ngx_raw_vs_hex(computed_sc.data, SHA_DIGEST_LENGTH,
submitted_sc.data, 2*SHA_DIGEST_LENGTH) == 0){
            if (sc[i].log == NGX_HTTP_SECRET_COOKIE_ON){
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   "secret_cookie: cookie \"%V\" is valid", &name);
            }
            goto secret_cookie_found;
        }
#if (NGX_DEBUG)
        ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                      "secret_cookie: cookie \"%V\" does not match",
&name);
#endif

secret_cookie_not_found:
        if (sc[i].log == NGX_HTTP_SECRET_COOKIE_ON){
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "secret_cookie: no valid cookie \"%V\" in header",
&name);
        }
        continue;

secret_cookie_found:
        // Append the found secret_cookie's name into
secret_cookie_value:
        p = ngx_copy(secret_cookie_value.data + secret_cookie_value.len,
name.data, name.len);
        *p = (u_char) NGX_HTTP_SECRET_COOKIE_DIVIDER; // Name is
separate by a space
        secret_cookie_value.len += name.len + 1;
    }
    // Setup the secret_cookie_value variable:
    ctx->secret_cookie_value->len = secret_cookie_value.len;
    ctx->secret_cookie_value->data = secret_cookie_value.data;
    ctx->secret_cookie_value->valid = 1;
    ctx->secret_cookie_value->no_cacheable = 1;
    ctx->secret_cookie_value->not_found = 0;

#if (NGX_DEBUG)
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
               "secret_cookie: The final secret_cookie_value has
length=%i and value=%V", secret_cookie_value.len,
&secret_cookie_value);
#endif
    // Return the result
    return ctx;
}

/* Add $secret_cookie_set variable to the http process.
 * Called by "preconfiguration" hook!
 */
static ngx_int_t
ngx_http_secret_cookie_add_variable(ngx_conf_t *cf)
{
    ngx_http_secret_cookie_variable_t *var;
    ngx_http_variable_t *v;

    for (var = ngx_http_secret_cookie_vars; var->name.len; var++) {

        v = ngx_http_add_variable(cf, &var->name,
NGX_HTTP_VAR_CHANGEABLE);
        if (v == NULL) {
            return NGX_ERROR;
        }

        v->get_handler = var->handler;
        v->data = var->data;
    }

    return NGX_OK;
}

/*
 * This function is called when location configuration is created.
 * It will create a default configuration for secret_cookie module.
 */
static void *
ngx_http_secret_cookie_create_conf(ngx_conf_t *cf)
{
    ngx_http_secret_cookie_conf_t *conf;

    conf = ngx_pcalloc(cf->pool,
sizeof(ngx_http_secret_cookie_conf_t));
    if (conf == NULL) {
        return NULL;
    }

    /*
     * Set by ngx_pcalloc():
     *
     * conf->secret_cookies = NULL;
     * conf->secret_cookies_value_disabled = NULL;
     */
    conf->status = NGX_CONF_UNSET;
    return conf;
}

/*
 * This function is called when location configuration is merged to main
config.
 * It will create a default configuration for secret_cookie module.
 */
static char *
ngx_http_secret_cookie_merge_conf(ngx_conf_t *cf, void *parent, void
*child)
{
    ngx_http_secret_cookie_conf_t *prev = parent;
    ngx_http_secret_cookie_conf_t *conf = child;
    u_char *p;
    ngx_str_t secret_cookie_value_disabled;
    ngx_uint_t i;
    ngx_http_secret_cookie_t *sc;

    // Merge previous to current configration, with a default value:
    ngx_conf_merge_value(conf->status, prev->status,
                              NGX_HTTP_SECRET_COOKIE_OFF);
    if (conf->secret_cookies == NULL){
        conf->secret_cookies = prev->secret_cookies;
        conf->secret_cookie_value_disabled =
prev->secret_cookie_value_disabled;
    } else {
        // Generate the disabled_value for this configuration:
        // First, count the required string length
        secret_cookie_value_disabled.len = 0;
        sc = conf->secret_cookies->elts;
        for (i=0; isecret_cookies->nelts; i++){
            secret_cookie_value_disabled.len += sc[i].name.len + 1;
        }
        // Secondly, create the buffer containing disabled_value

        secret_cookie_value_disabled.data = ngx_pcalloc(cf->pool,
secret_cookie_value_disabled.len);
        if (secret_cookie_value_disabled.data == NULL){
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                        "Not enough memory for
secret_cookie_value_disabled string");
            return NGX_CONF_ERROR;
        }
        // Thirdly, copy all secret cookie's name to disabled_value
        p = secret_cookie_value_disabled.data;
        for (i=0; isecret_cookies->nelts; i++){
            p = ngx_copy(p, sc[i].name.data, sc[i].name.len);
            *p = (u_char) NGX_HTTP_SECRET_COOKIE_DIVIDER; // Name is
separate by a space
            p++;
        }
#if (NGX_DEBUG)
        ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0,
              "String secret_cookie_value_disabled has length = %i and
value = %V", secret_cookie_value_disabled.len,
&secret_cookie_value_disabled);
#endif
        conf->secret_cookie_value_disabled = ngx_pcalloc(cf->pool,
sizeof(ngx_http_variable_value_t));
        if (conf->secret_cookie_value_disabled == NULL){
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                        "Not enough memory for
conf->secret_cookie_value_disabled variable");
            return NGX_CONF_ERROR;
        }
        conf->secret_cookie_value_disabled->len =
secret_cookie_value_disabled.len;
        conf->secret_cookie_value_disabled->valid = 1;
        conf->secret_cookie_value_disabled->no_cacheable = 1;
        conf->secret_cookie_value_disabled->not_found = 0;
        conf->secret_cookie_value_disabled->data =
secret_cookie_value_disabled.data;
    }

    return NGX_CONF_OK;
}

/*
 * This function is called after secret_cookie_def is passed
 * from config to module. Here you can validate the param, or change the

 * param to meaningful value.
 */
static char *
ngx_http_secret_cookie_def(ngx_conf_t *cf, ngx_command_t *cmd, void
*conf)
{
    ngx_http_secret_cookie_conf_t *sccf = conf;

    ngx_uint_t n, i, anumber;
    u_char c;
    ngx_str_t *value;
    ngx_http_secret_cookie_t *sc;

    // Create secret_cookies array to hold definitions
    if (sccf->secret_cookies == NULL){
        sccf->secret_cookies = ngx_array_create(cf->pool, 3,

sizeof(ngx_http_secret_cookie_t));
        if (sccf->secret_cookies == NULL){
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                        "Not enough memory for sccf->secret_cookies
array");
            return NGX_CONF_ERROR;
        }
    }
    // Create new element in the array to hold one definition
    sc = ngx_array_push(sccf->secret_cookies);
    if (sc == NULL) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "Not enough memory for new element in
sccf->secret_cookies array");
        return NGX_CONF_ERROR;
    }
    // Process the parameters
    sc->status = NGX_HTTP_SECRET_COOKIE_ON;
    sc->log = NGX_HTTP_SECRET_COOKIE_OFF;
    sc->ua_limit = 0;
    value = cf->args->elts;
    for (n=1; n < cf->args->nelts; n++){
        // off
        if (ngx_strncmp(value[n].data,"off",3)==0){
            sc->status = NGX_HTTP_SECRET_COOKIE_OFF;
            continue;
        }
        // log
        if (ngx_strncmp(value[n].data,"log=on",6)==0){
            sc->log = NGX_HTTP_SECRET_COOKIE_ON;
            continue;
        }
        //ua_limit=
        if (ngx_strncmp(value[n].data, "ua_limit=", 9) == 0){
            // Convert ua_limit to number:
            anumber = 0;
            for (i=9; i < value[n].len; i++){
                c = value[n].data[i];
                if (c >= '0' && c <= '9'){
                    anumber = anumber*10 + (c - '0');
                    continue;
                }
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "Invalid \"ua_limit\" (must be an integer)");
                return NGX_CONF_ERROR;
            }
            // Validate the ua_limit:
            if ((anumber > 0) && (anumber <
NGX_HTTP_SECRET_COOKIE_MINIMUM_UA_LIMIT)){
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "Invalid \"ua_limit\" (must be greater than
%i)", NGX_HTTP_SECRET_COOKIE_MINIMUM_UA_LIMIT);
                return NGX_CONF_ERROR;
            }
            sc->ua_limit = anumber;
            continue;
        }
        // name=
        if (ngx_strncmp(value[n].data, "name=", 5) == 0){
            sc->name.len = value[n].len - 5;
            if ((sc->name.len < 1) || (sc->name.len >
NGX_HTTP_SECRET_COOKIE_MAX_SHORT_STR_SIZE)){
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "Parameter \"name\" is empty or too long");
                return NGX_CONF_ERROR;
            }
            sc->name.data = value[n].data + 5;
            continue;
        }
        // salt=
        if (ngx_strncmp(value[n].data, "salt=", 5) == 0){
            sc->salt.len = value[n].len - 5;
            if ((sc->salt.len < 1) || (sc->salt.len >
NGX_HTTP_SECRET_COOKIE_MAX_SHORT_STR_SIZE)){
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "Parameter \"salt\" is empty or too long");
                return NGX_CONF_ERROR;
            }
            sc->salt.data = value[n].data + 5;
            continue;
        }
        // rule=
        if (ngx_strncmp(value[n].data, "rule=", 5) == 0){
            // Validate the rule:
            for (i=5; i < value[n].len; i++){
                c = ngx_tolower(value[n].data[i]);
                switch (c){
                    case NGX_HTTP_SECRET_COOKIE_RULE_ADDRESS:
                    case NGX_HTTP_SECRET_COOKIE_RULE_TIME:
                    case NGX_HTTP_SECRET_COOKIE_RULE_SALT:
                    case NGX_HTTP_SECRET_COOKIE_RULE_USER_AGENT:
                        break;
                    default:
                        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "Rule does not accept characters other than
\"a\", \"t\", \"s\" and \"u\"");
                        return NGX_CONF_ERROR;
                }
            }

            sc->rule.len = value[n].len - 5;
            if ((sc->rule.len < 1) || (sc->rule.len >
NGX_HTTP_SECRET_COOKIE_MAX_SHORT_STR_SIZE)){
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "Parameter \"rule\" is empty or too long");
                return NGX_CONF_ERROR;
            }
            sc->rule.data = value[n].data + 5;
            continue;
        }
        // duration
        if (ngx_strncmp(value[n].data, "duration=", 9) == 0){
            // Convert duration to number:
            anumber = 0;
            for (i=9; i < value[n].len; i++){
                c = value[n].data[i];
                if (c >= '0' && c <= '9'){
                    anumber = anumber*10 + (c - '0');
                    continue;
                }
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "Invalid \"duration\" (must be an integer)");
                return NGX_CONF_ERROR;
            }
            // Validate the duration:
            if (anumber < NGX_HTTP_SECRET_COOKIE_MINIMUM_DURATION){
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "Invalid \"duration\" (must be greater than
%i)", NGX_HTTP_SECRET_COOKIE_MINIMUM_DURATION);
                return NGX_CONF_ERROR;
            }
            sc->duration = anumber;
            continue;
        }
    }

    if (sc->rule.data == NULL){
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "The required parameter \"rule\" is
missing!");
        return NGX_CONF_ERROR;
    }
    if (sc->salt.data == NULL){
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "The required parameter \"salt\" is
missing!");
        return NGX_CONF_ERROR;
    }
    if (sc->name.data == NULL){
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "The required parameter \"name\" is
missing!");
        return NGX_CONF_ERROR;
    }
    if (sc->duration == 0){
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                         "The required parameter \"duration\" is
missing");
        return NGX_CONF_ERROR;
    }
#if (NGX_DEBUG)
    ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0,
                   "Secret_cookie_def: on/off=%i name=%V salt=%V rule=%V
duration=%i",
                   sc->status, &sc->name, &sc->salt, &sc->rule,
sc->duration);
#endif
    return NGX_CONF_OK;
}

/*
 * Convert an int64 to string presentation
 */
static u_char * ngx_num2str(u_char *buf, u_char *last, uint64_t ui64)
{
    u_char *p, temp[NGX_INT64_LEN + 1];
                       /*
                        * we need temp[NGX_INT64_LEN] only,
                        * but icc issues the warning
                        */
    size_t len;
    uint32_t ui32;

    p = temp + NGX_INT64_LEN;

    if (ui64 <= NGX_MAX_UINT32_VALUE) {
        ui32 = (uint32_t) ui64;

        do {
            *--p = (u_char) (ui32 % 10 + '0');
        } while (ui32 /= 10);

    } else {
        do {
            *--p = (u_char) (ui64 % 10 + '0');
        } while (ui64 /= 10);
    }

    /* number safe copy */

    len = (temp + NGX_INT64_LEN) - p;

    if (buf + len > last) {
        len = last - buf;
    }

    return ngx_cpymem(buf, p, len);
}

/*
 * Comparison of a raw string and a hex-style string
 */
static ngx_int_t ngx_raw_vs_hex(u_char *rawbuf, size_t rlen, u_char
*hexbuf, size_t hlen)
{
    static u_char hex[] = "0123456789abcdef";
    u_char hexchar[] = "aa";
    ngx_int_t len, i;
    // Compare by the shortest length
    len = ((rlen < hlen / 2) ? rlen : hlen / 2);
    i = 0;
    while (i < len){
        // Calculate a hexchar from rawbuff
        hexchar[1] = hex[rawbuf[i] & 0xf];
        hexchar[0] = hex[(rawbuf[i]>>4) & 0xf];
        if ((hexchar[0] != hexbuf[2*i]) || (hexchar[1] !=
hexbuf[2*i+1])){
            return 1;
        }
        i++;
    }
    return 0;
}
```

Posted at Nginx Forum:

> **[Re: Redirect based on php-set cookies](https://forum.nginx.org/read.php?2,55378,173796#msg-173796)**
>
> Hi guys, I am planning to use nginx as reserve proxy in front my Apache server. Our site is under heavy DoS attack, where attacker sends a lot of malformed HTTP request to flood Apache. I intend to filter out the attacker by: - Setting up nginx as...
