├── README.md ├── config ├── lib ├── captcha.h ├── cookie.h └── hash.h └── ngx_http_captcha.c /README.md: -------------------------------------------------------------------------------- 1 | # ngx_http_captcha 2 | ![image](https://user-images.githubusercontent.com/30780133/203496892-69e6142d-57cc-4498-a895-39e58052454e.png) 3 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_my_module 2 | 3 | 4 | 5 | EXECUTE_SRCS=" \ 6 | $ngx_addon_dir/ngx_http_captcha.c \ 7 | " 8 | 9 | 10 | EXECUTE_DEPS=" \ 11 | " 12 | 13 | if test -n "$ngx_module_link"; then 14 | ngx_module_type=HTTP 15 | ngx_module_name=ngx_http_captcha_module 16 | ngx_module_srcs="$ngx_addon_dir/ngx_http_captcha.c" 17 | ngx_module_libs="-lgd" 18 | . auto/module 19 | else 20 | HTTP_MODULES="$HTTP_MODULES ngx_http_captcha_module" 21 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $EXECUTE_SRCS" 22 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $EXECUTE_DEPS" 23 | ngx_module_libs="-lgd" 24 | ngx_module_incs="$ngx_waf_incs" 25 | fi 26 | 27 | -------------------------------------------------------------------------------- /lib/captcha.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define CAPTCHA_HEIGHT 70 6 | 7 | #define CAPTCHA_CHAR_ANGLE (M_PI/8) 8 | 9 | #define CHAR_PIXEL_LENGTH 40 10 | 11 | struct Captcha *create(int ,int ,int , char *, char *); 12 | void generate_captcha(struct Captcha *); 13 | void add_chars(struct Captcha *); 14 | void add_lines(struct Captcha *); 15 | void destroy_captcha(struct Captcha *); 16 | static double _norm_random_captcha(); 17 | 18 | struct Captcha{ 19 | gdImagePtr im; 20 | int r, g, b; 21 | int char_length, number_of_lines, height, char_pixel_length; 22 | char *charset, *font; 23 | unsigned char *message; 24 | unsigned char *buf; 25 | int size; 26 | }; 27 | 28 | 29 | static double _norm_random_captcha() { 30 | return rand() / (double)RAND_MAX * 2 - 1; 31 | } 32 | 33 | struct Captcha *create(int char_length,int number_of_lines,int char_pixel_length, char *charset, char *font){ 34 | struct Captcha *captcha = malloc(sizeof(struct Captcha)); 35 | 36 | //define colors range 37 | captcha-> r = (int)rand()%(50)+200; 38 | captcha-> g = (int)rand()%(50); 39 | captcha-> b = (int)rand()%(50); 40 | 41 | captcha->char_length = char_length; 42 | captcha->number_of_lines = number_of_lines; 43 | captcha->height = CAPTCHA_HEIGHT; 44 | captcha->char_pixel_length = char_pixel_length; 45 | 46 | captcha->charset = strdup(charset); 47 | captcha->font = strdup(font); 48 | 49 | captcha->message = malloc(sizeof(char) * captcha->char_length); 50 | 51 | return captcha; 52 | } 53 | 54 | 55 | void generate_captcha(struct Captcha *captcha){ 56 | captcha->im = gdImageCreate(captcha->char_length * captcha->char_pixel_length, CAPTCHA_HEIGHT); 57 | gdImageColorAllocate(captcha->im, 255, 255, 255); 58 | 59 | add_chars(captcha); 60 | add_lines(captcha); 61 | 62 | } 63 | 64 | void get_binary(struct Captcha *captcha){ 65 | //get image to bytes 66 | if (!captcha->im){ 67 | printf("nulll"); 68 | return ; 69 | } 70 | captcha->buf= (unsigned char*)gdImagePngPtr(captcha->im, &captcha->size); 71 | } 72 | 73 | 74 | void add_chars(struct Captcha *captcha){ 75 | int color_text = gdImageColorAllocate(captcha->im, captcha->r, captcha->g, captcha->b); 76 | 77 | int brect[8]; 78 | char current_char[2] = { 0 }; 79 | //add chars to captcha 80 | int i=0; 81 | while (1){ 82 | current_char[0]=captcha->charset[rand() % (int)(strlen(captcha->charset) -1)]; 83 | captcha->message[i]=(unsigned char)current_char[0]; 84 | gdImageStringFT( captcha->im, brect, color_text,captcha->font, 85 | 30, CAPTCHA_CHAR_ANGLE * _norm_random_captcha(), 86 | (captcha->char_pixel_length*i)+10, 50, current_char 87 | ); 88 | 89 | gdFreeFontCache (); 90 | if ( i++ == captcha->char_length - 1){ 91 | gdFontCacheShutdown (); 92 | break;colors 93 | } 94 | } 95 | 96 | } 97 | 98 | void add_lines(struct Captcha *captcha){ 99 | int x1, y1, x2, y2; 100 | for (int i=0; i< captcha->number_of_lines; i++){ 101 | 102 | x1 = (int)rand()%(captcha->char_pixel_length * captcha->char_length); 103 | x2 = (int)rand()%(captcha->char_pixel_length * captcha->char_length); 104 | y1 = (int)rand()%(captcha->height); 105 | y2 = (int)rand()%(captcha->height); 106 | 107 | gdImageLine( captcha->im, 108 | x1, y1, 109 | x2, y2, 110 | gdImageColorAllocate(captcha->im, 0,0,0) 111 | ); 112 | } 113 | } 114 | 115 | void destroy_captcha(struct Captcha *captcha){ 116 | if (captcha-> im){ 117 | gdImageDestroy(captcha->im); 118 | } 119 | free (captcha->charset); 120 | free (captcha->font); 121 | free (captcha->buf); 122 | free (captcha->message); 123 | free (captcha); 124 | } 125 | -------------------------------------------------------------------------------- /lib/cookie.h: -------------------------------------------------------------------------------- 1 | 2 | #define CAPTCHA_COOKIE_NAME "captcha_code" 3 | #define COOKIE_LEN 128 4 | 5 | 6 | typedef struct _ngx_captcha_cookie{ 7 | ngx_str_t path; 8 | ngx_str_t domain; 9 | ngx_str_t expire; 10 | ngx_str_t name; 11 | ngx_str_t value; 12 | } ngx_captcha_cookie; 13 | 14 | static ngx_captcha_cookie * generate_captcha_cookie(ngx_http_request_t *req, u_char* captcha_code) 15 | { 16 | u_char * value; 17 | size_t value_len; 18 | u_char * expire, *p; 19 | size_t expire_len; 20 | size_t exp_len; 21 | 22 | ngx_captcha_cookie * captcha_cookie; 23 | 24 | captcha_cookie = (ngx_captcha_cookie *)ngx_pcalloc(req->pool, sizeof(ngx_captcha_cookie));//alloc 1 25 | 26 | value = captcha_code; 27 | value_len = COOKIE_LEN; //to do modify size 28 | 29 | exp_len = ngx_strlen("; expires="); 30 | expire = (u_char *)ngx_pcalloc(req->pool, exp_len+40);//alloc 2 31 | p = expire; 32 | p = ngx_copy(p, "; expires=", exp_len); 33 | p = ngx_http_cookie_time(p, ngx_time()+ 8*3600 ); 34 | expire_len = ngx_strlen((const char *)expire); 35 | 36 | captcha_cookie->name.data = (u_char *)CAPTCHA_COOKIE_NAME; 37 | captcha_cookie->name.len = strlen(CAPTCHA_COOKIE_NAME); 38 | captcha_cookie->value.data = value; 39 | captcha_cookie->value.len = value_len; 40 | captcha_cookie->expire.data = expire; 41 | captcha_cookie->expire.len = expire_len; 42 | captcha_cookie->path.data = (u_char *)"; path=/;"; 43 | captcha_cookie->path.len = ngx_strlen("; path=/;"); 44 | 45 | return captcha_cookie; 46 | } 47 | 48 | 49 | 50 | /** 51 | * set cookie to header 52 | */ 53 | static ngx_int_t set_captcha_cookie(ngx_http_request_t *req, u_char* captcha_code) 54 | { 55 | u_char *cookie, *p; 56 | size_t len; 57 | ngx_table_elt_t *set_cookie; 58 | 59 | ngx_captcha_cookie * captcha_cookie = generate_captcha_cookie(req, captcha_code); 60 | 61 | len = captcha_cookie->name.len+1+captcha_cookie->value.len; 62 | 63 | if (captcha_cookie->expire.len) { 64 | len += captcha_cookie->expire.len; 65 | } 66 | 67 | if (captcha_cookie->path.len) { 68 | len += captcha_cookie->path.len; 69 | } 70 | 71 | cookie = ngx_pnalloc(req->pool, len); //alloc 3 72 | 73 | if (cookie == NULL) { 74 | ngx_log_error(NGX_LOG_ERR, req->connection->log, 0,"cookie ngx_pnalloc error length[%d]",len); 75 | return NGX_ERROR; 76 | } 77 | 78 | p = ngx_copy(cookie, captcha_cookie->name.data, captcha_cookie->name.len); 79 | *p++ = '='; 80 | p = ngx_copy(p, captcha_cookie->value.data, captcha_cookie->value.len); 81 | 82 | if (captcha_cookie->expire.len) { 83 | p = ngx_copy(p, captcha_cookie->expire.data, captcha_cookie->expire.len); 84 | } 85 | 86 | if (captcha_cookie->path.len) { 87 | p = ngx_copy(p, captcha_cookie->path.data, captcha_cookie->path.len); 88 | } 89 | 90 | 91 | ngx_pfree(req->pool, captcha_cookie->expire.data); //free 2 92 | ngx_pfree(req->pool, captcha_cookie); //free 1 93 | 94 | set_cookie = ngx_list_push(&req->headers_out.headers); 95 | if (set_cookie == NULL) { 96 | ngx_log_error(NGX_LOG_ERR, req->connection->log, 0,"set_cookie ngx_list_push error cookie[%s]", cookie); 97 | return NGX_ERROR; 98 | } 99 | 100 | set_cookie->hash = 1; 101 | ngx_str_set(&set_cookie->key, "Set-Cookie"); 102 | set_cookie->value.len = p - cookie; 103 | set_cookie->value.data = cookie; 104 | 105 | 106 | ngx_pfree(req->pool, cookie); //free 3 107 | 108 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0,"captcha cookie: \"%V\"", &set_cookie->value); 109 | 110 | 111 | return NGX_OK; 112 | } 113 | 114 | 115 | 116 | /** 117 | * get cookie from header 118 | */ 119 | int get_cookie(ngx_http_request_t *r, ngx_str_t *name, ngx_str_t *value) { 120 | #if defined(nginx_version) && nginx_version >= 1023000 121 | ngx_table_elt_t *h; 122 | for (h = r->headers_in.cookie; h; h = h->next) { 123 | u_char *start = h->value.data; 124 | u_char *end = h->value.data + h->value.len; 125 | // ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ HEADERS ] > %s < ",h->value.data ); 126 | #else 127 | ngx_table_elt_t **h; 128 | h = r->headers_in.cookies.elts; 129 | ngx_uint_t i = 0; 130 | for (i = 0; i < r->headers_in.cookies.nelts; i++) { 131 | u_char *start = h[i]->value.data; 132 | u_char *end = h[i]->value.data + h[i]->value.len; 133 | // ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ HEADERS ] > %s < ",h[i]->value.data ); 134 | #endif 135 | while (start < end) { 136 | while (start < end && *start == ' ') { start++; } 137 | //get cookie 138 | if (ngx_strncmp(start, name->data, name->len) == 0) { 139 | u_char *last; 140 | for (last = start; last < end && *last != ';'; last++) { 141 | //ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ %c ] ",*last ); 142 | } 143 | while (*start++ != '=' && start < last) {} 144 | 145 | value->data = start; 146 | value->len = (last - start); 147 | 148 | // ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ %d - %d] ",last, start ); 149 | return 0; 150 | } 151 | while (*start++ != ';' && start < end) {} 152 | } 153 | } 154 | 155 | return -1; 156 | } 157 | 158 | -------------------------------------------------------------------------------- /lib/hash.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef SHA512_H 4 | #define SHA512_H 5 | 6 | 7 | typedef struct 8 | { 9 | unsigned long long count[2]; 10 | unsigned long long state[8]; 11 | unsigned char buffer[128]; 12 | } SHA512_CB; 13 | 14 | unsigned char PADDING[] = { 15 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19 | }; 20 | 21 | static const unsigned long long K[80] = { 22 | 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 23 | 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 24 | 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 25 | 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 26 | 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 27 | 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 28 | 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 29 | 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 30 | 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 31 | 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 32 | 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 33 | 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 34 | 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 35 | 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 36 | 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 37 | 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 38 | 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 39 | 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 40 | 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 41 | 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL 42 | }; 43 | 44 | void SHA512Init(SHA512_CB *context); 45 | 46 | void SHA512Update(SHA512_CB *context, unsigned char *input, unsigned long long inputlen); 47 | 48 | void SHA512Final(SHA512_CB *context, unsigned char digest[32]); 49 | 50 | void SHA512Transform(unsigned long long state[8], unsigned char block[128]); 51 | 52 | void SHA512Encode(unsigned char *output, unsigned long long *input, unsigned long long len); 53 | 54 | void SHA512convert2Char(unsigned char *sha512Code, char *sha512input ); 55 | 56 | void SHA512Decode(unsigned long long *output, unsigned char *input, unsigned long long len); 57 | #endif 58 | 59 | 60 | #define ROR64( value, bits ) (((value) >> (bits)) | ((value) << (64 - (bits)))) 61 | 62 | 63 | #define Ch( x, y, z ) (z ^ (x & (y ^ z))) 64 | #define Maj(x, y, z ) (((x | y) & z) | (x & y)) 65 | #define S( x, n ) ROR64( x, n ) 66 | #define R( x, n ) (((x)&0xFFFFFFFFFFFFFFFFULL)>>((unsigned long long)n)) 67 | #define Sigma0( x ) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) 68 | #define Sigma1( x ) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) 69 | #define Gamma0( x ) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) 70 | #define Gamma1( x ) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) 71 | 72 | #define Sha512Round( a, b, c, d, e, f, g, h, i ) \ 73 | t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ 74 | t1 = Sigma0(a) + Maj(a, b, c); \ 75 | d += t0; \ 76 | h = t0 + t1; 77 | 78 | void SHA512Init(SHA512_CB *context) { 79 | context->count[0] = 0; 80 | context->count[1] = 0; 81 | context->state[0] = 0x6a09e667f3bcc908ULL; 82 | context->state[1] = 0xbb67ae8584caa73bULL; 83 | context->state[2] = 0x3c6ef372fe94f82bULL; 84 | context->state[3] = 0xa54ff53a5f1d36f1ULL; 85 | context->state[4] = 0x510e527fade682d1ULL; 86 | context->state[5] = 0x9b05688c2b3e6c1fULL; 87 | context->state[6] = 0x1f83d9abfb41bd6bULL; 88 | context->state[7] = 0x5be0cd19137e2179ULL; 89 | } 90 | 91 | void SHA512Update(SHA512_CB *context, unsigned char *input, unsigned long long inputlen) { 92 | unsigned long long index = 0, partlen = 0, i = 0; 93 | index = (context->count[1] >> 3) & 0x7F; 94 | partlen = 128 - index; 95 | context->count[1] += inputlen << 3; 96 | 97 | if (context->count[1] < (inputlen << 3)) 98 | context->count[0]++; 99 | context->count[0] += inputlen >> 61; 100 | 101 | 102 | 103 | if (inputlen >= partlen) 104 | { 105 | 106 | memcpy(&context->buffer[index], input, partlen); 107 | SHA512Transform(context->state, context->buffer); 108 | 109 | 110 | for (i = partlen; i + 128 <= inputlen; i += 128) 111 | SHA512Transform(context->state, &input[i]); 112 | index = 0; 113 | } 114 | else 115 | { 116 | i = 0; 117 | } 118 | memcpy(&context->buffer[index], &input[i], inputlen - i); 119 | } 120 | 121 | void SHA512Final(SHA512_CB *context, unsigned char digest[64]) { 122 | unsigned int index = 0, padlen = 0; 123 | unsigned char bits[16]; 124 | index = (context->count[1] >> 3) & 0x7F; 125 | padlen = (index < 112) ? (112 - index) : (240 - index); 126 | SHA512Encode(bits, context->count, 16); 127 | SHA512Update(context, PADDING, padlen); 128 | SHA512Update(context, bits, 16); 129 | SHA512Encode(digest, context->state, 64); 130 | } 131 | 132 | void SHA512Encode(unsigned char *output, unsigned long long *input, unsigned long long len) { 133 | unsigned long long i = 0, j = 0; 134 | while (j < len) 135 | { 136 | output[j+7] = input[i] & 0xFF; 137 | output[j + 6] = (input[i] >> 8) & 0xFF; //0xFF:11111111 138 | output[j + 5] = (input[i] >> 16) & 0xFF; 139 | output[j + 4] = (input[i] >> 24) & 0xFF; 140 | output[j + 3] = (input[i] >> 32) & 0xFF; 141 | output[j + 2] = (input[i] >> 40) & 0xFF; 142 | output[j + 1] = (input[i] >> 48) & 0xFF; 143 | output[j] = (input[i] >> 56) & 0xFF; 144 | i++; 145 | j += 8; 146 | } 147 | } 148 | 149 | 150 | void SHA512Decode(unsigned long long *output, unsigned char *input, unsigned long long len) { 151 | unsigned long long i = 0, j = 0; 152 | while (j < len) 153 | { 154 | output[i] = ((unsigned long long)input[j+7]) | 155 | ((unsigned long long)input[j + 6] << 8) | 156 | ((unsigned long long)input[j + 5] << 16) | 157 | ((unsigned long long)input[j + 4] << 24) | 158 | ((unsigned long long)input[j + 3] << 32) | 159 | ((unsigned long long)input[j + 2] << 40) | 160 | ((unsigned long long)input[j + 1] << 48) | 161 | ((unsigned long long)input[j] << 56); 162 | i++; 163 | j += 8; 164 | } 165 | } 166 | 167 | void SHA512Transform(unsigned long long state[8], unsigned char block[128]) { 168 | unsigned long long S[8]; 169 | unsigned long long W[80]; 170 | unsigned long long t0; 171 | unsigned long long t1; 172 | int i = 0; 173 | 174 | for ( i = 0; i < 8; i++ ) 175 | { 176 | S[i] = state[i]; 177 | } 178 | 179 | SHA512Decode(W, block, 128); 180 | 181 | for ( i = 16; i < 80; i++ ) 182 | { 183 | W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; 184 | } 185 | 186 | for ( i = 0; i < 80; i += 8 ) 187 | { 188 | Sha512Round(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0); 189 | Sha512Round(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1); 190 | Sha512Round(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2); 191 | Sha512Round(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3); 192 | Sha512Round(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4); 193 | Sha512Round(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5); 194 | Sha512Round(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6); 195 | Sha512Round(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7); 196 | } 197 | 198 | for ( i = 0; i < 8; i++ ) 199 | { 200 | state[i] = state[i] + S[i]; 201 | } 202 | } 203 | 204 | 205 | static void buf2hex(const unsigned char *buf, size_t buflen, unsigned char *hex_string) { 206 | static const char hexdig[] = "0123456789ABCDEF"; 207 | 208 | const unsigned char *p; 209 | size_t i; 210 | 211 | int j=0; 212 | unsigned char *s = hex_string; 213 | for (i = 0, p = buf; i < buflen; i++, p++) { 214 | *s++ = hexdig[(*p >> 4) & 0x0f]; 215 | *s++ = hexdig[*p & 0x0f]; 216 | j++; 217 | } 218 | 219 | printf("t=%d\n", j); 220 | } 221 | 222 | void mySHA512(unsigned char* input, unsigned char * output){ 223 | //check output dimensions 224 | SHA512_CB sha512; 225 | SHA512Init(&sha512); 226 | SHA512Update(&sha512, input, strlen((char *)input)); 227 | SHA512Final(&sha512, output); 228 | 229 | } 230 | 231 | 232 | unsigned long hash(ngx_http_request_t *r, unsigned char *s, int size) 233 | { 234 | //ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ hash ] , msg=%s msg_len = %d", s, size); 235 | 236 | unsigned long hashval; 237 | int i=0; 238 | for (hashval = 0; *s != '\0'; s++){ 239 | 240 | 241 | hashval = *s + 31*hashval; 242 | if ( i++ == size ) break; 243 | } 244 | 245 | hashval = hashval % 100000000000000; 246 | //padding n elements 247 | while (hashval < 100000000000000 && hashval > 0){ 248 | hashval*=10; 249 | hashval=hashval^(rand()%10); 250 | } 251 | 252 | return hashval; 253 | } 254 | 255 | 256 | -------------------------------------------------------------------------------- /ngx_http_captcha.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "lib/captcha.h" 7 | #include "lib/hash.h" 8 | #include "lib/cookie.h" 9 | 10 | 11 | #define DEFAULT_SECRET "changeme" 12 | //define chars 13 | #define CAPTCHA_CHARSET "abcdefghijmnpqrtvwxyzABCDEFGHIJLMNPQRTVWXYZ123456789#@%" 14 | //define font 15 | #define CAPTCHA_FONT "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" 16 | //define number of chars 17 | #define CAPTCHA_CHAR_LENGTH 6 18 | //define number of line 19 | #define CAPTCHA_NUMBER_OF_LINES 7 20 | 21 | 22 | int get_cookie(ngx_http_request_t *, ngx_str_t *, ngx_str_t *); 23 | static ngx_int_t set_captcha_cookie(ngx_http_request_t *, u_char* ); 24 | static ngx_int_t ngx_http_captcha(ngx_conf_t *); 25 | static ngx_int_t ngx_http_captcha_handler(ngx_http_request_t *); 26 | static void *ngx_http_captcha_create_loc_conf(ngx_conf_t *); 27 | static char *ngx_http_captcha_merge_loc_conf(ngx_conf_t *, void *, void *); 28 | 29 | #define SHA_LEN 128 30 | 31 | 32 | typedef struct { 33 | ngx_flag_t enabled; 34 | ngx_uint_t bucket_duration; 35 | ngx_uint_t captcha_length; 36 | ngx_str_t secret; 37 | ngx_str_t captcha_font; 38 | ngx_str_t captcha_charset; 39 | } ngx_http_captcha_loc_conf_t; 40 | 41 | 42 | static ngx_command_t ngx_http_captcha_commands[] = { 43 | { 44 | ngx_string("captcha"), 45 | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_HTTP_SIF_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_FLAG, 46 | ngx_conf_set_flag_slot, 47 | NGX_HTTP_LOC_CONF_OFFSET, 48 | offsetof(ngx_http_captcha_loc_conf_t, enabled), 49 | NULL 50 | }, 51 | { 52 | ngx_string("captcha_bucket_duration"), 53 | NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1, 54 | ngx_conf_set_num_slot, 55 | NGX_HTTP_LOC_CONF_OFFSET, 56 | offsetof(ngx_http_captcha_loc_conf_t, bucket_duration), 57 | NULL 58 | }, 59 | { 60 | ngx_string("captcha_length"), 61 | NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1, 62 | ngx_conf_set_num_slot, 63 | NGX_HTTP_LOC_CONF_OFFSET, 64 | offsetof(ngx_http_captcha_loc_conf_t, captcha_length), 65 | NULL 66 | }, 67 | { 68 | ngx_string("captcha_secret"), 69 | NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1, 70 | ngx_conf_set_str_slot, 71 | NGX_HTTP_LOC_CONF_OFFSET, 72 | offsetof(ngx_http_captcha_loc_conf_t, secret), 73 | NULL 74 | }, 75 | { 76 | ngx_string("captcha_font"), 77 | NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1, 78 | ngx_conf_set_str_slot, 79 | NGX_HTTP_LOC_CONF_OFFSET, 80 | offsetof(ngx_http_captcha_loc_conf_t, captcha_font), 81 | NULL 82 | }, 83 | { 84 | ngx_string("captcha_charset"), 85 | NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1, 86 | ngx_conf_set_str_slot, 87 | NGX_HTTP_LOC_CONF_OFFSET, 88 | offsetof(ngx_http_captcha_loc_conf_t, captcha_charset), 89 | NULL 90 | }, 91 | ngx_null_command 92 | }; 93 | 94 | 95 | static ngx_http_module_t ngx_http_captcha_module_ctx = { 96 | NULL, 97 | ngx_http_captcha, 98 | NULL, 99 | NULL, 100 | NULL, 101 | NULL, 102 | ngx_http_captcha_create_loc_conf, 103 | ngx_http_captcha_merge_loc_conf 104 | }; 105 | 106 | ngx_module_t ngx_http_captcha_module = { 107 | NGX_MODULE_V1, 108 | &ngx_http_captcha_module_ctx, 109 | ngx_http_captcha_commands, 110 | NGX_HTTP_MODULE, 111 | NULL, 112 | NULL, 113 | NULL, 114 | NULL, 115 | NULL, 116 | NULL, 117 | NULL, 118 | NGX_MODULE_V1_PADDING 119 | }; 120 | 121 | 122 | static void *ngx_http_captcha_create_loc_conf(ngx_conf_t *cf) { 123 | ngx_http_captcha_loc_conf_t *conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_captcha_loc_conf_t)); 124 | if (conf == NULL) { 125 | return NGX_CONF_ERROR; 126 | } 127 | 128 | conf->secret = (ngx_str_t) {0, NULL}; 129 | conf->bucket_duration = NGX_CONF_UNSET_UINT; 130 | conf->captcha_length = NGX_CONF_UNSET_UINT; 131 | conf->enabled = NGX_CONF_UNSET; 132 | 133 | return conf; 134 | } 135 | 136 | 137 | static char *ngx_http_captcha_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) { 138 | ngx_http_captcha_loc_conf_t *prev = parent; 139 | ngx_http_captcha_loc_conf_t *conf = child; 140 | 141 | ngx_conf_merge_uint_value(conf->bucket_duration, prev->bucket_duration, 3600) 142 | ngx_conf_merge_uint_value(conf->captcha_length, prev->captcha_length, CAPTCHA_CHAR_LENGTH) 143 | ngx_conf_merge_value(conf->enabled, prev->enabled, 0) 144 | ngx_conf_merge_str_value(conf->secret, prev->secret, DEFAULT_SECRET) 145 | ngx_conf_merge_str_value(conf->captcha_font, prev->captcha_font, CAPTCHA_FONT) 146 | ngx_conf_merge_str_value(conf->captcha_charset, prev->captcha_charset, CAPTCHA_CHARSET) 147 | 148 | if (conf->bucket_duration < 1) { 149 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "bucket_duration must be equal or more than 1"); 150 | return NGX_CONF_ERROR; 151 | } 152 | 153 | return NGX_CONF_OK; 154 | } 155 | 156 | 157 | //

Enter the code above here :



158 | //https://www.javascriptobfuscator.com/Javascript-Obfuscator.aspx -> javascript 159 | //http://snapbuilder.com/code_snippet_generator/obfuscate_html_source_code/ ->html 160 | int serve_HTML(ngx_http_request_t *r) { 161 | unsigned char buf[] = {""}; 162 | 163 | size_t sz = strlen((char *)buf); 164 | static const ngx_str_t content_type = ngx_string("text/html;charset=utf-8;"); 165 | r->headers_out.status = NGX_HTTP_OK; 166 | r->headers_out.content_length_n = sz; 167 | 168 | r->headers_out.content_type = content_type; 169 | ngx_http_send_header(r); 170 | 171 | ngx_buf_t *b; 172 | ngx_chain_t out; 173 | 174 | b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); 175 | 176 | out.buf = b; 177 | out.next = NULL; 178 | 179 | b->pos = buf; 180 | b->last = buf + sz; 181 | b->memory = 1; 182 | b->last_buf = 1; 183 | 184 | ngx_http_output_filter(r, &out); 185 | ngx_http_finalize_request(r, 0); 186 | 187 | return NGX_DONE; 188 | } 189 | 190 | 191 | 192 | 193 | /** 194 | * serve captcha image 195 | ex: 196 | HTTP/1.1 200 OK\r\n 197 | Content-Type: image/png\r\n 198 | Content-Length: [length in bytes of the image]\r\n 199 | Set-Cookie: [hash(captcha)]\r\n 200 | \r\n 201 | [binary data of your image] 202 | */ 203 | int serve_captcha(ngx_http_request_t *r, ngx_http_captcha_loc_conf_t *conf){ 204 | //create captcha 205 | struct Captcha *captcha=create( 206 | conf->captcha_length, CAPTCHA_NUMBER_OF_LINES, CHAR_PIXEL_LENGTH, 207 | (char *)conf->captcha_charset.data, (char *)conf->captcha_font.data 208 | ); 209 | generate_captcha(captcha); 210 | get_binary(captcha); 211 | 212 | static const ngx_str_t content_type = ngx_string("image/png;"); 213 | 214 | r->headers_out.status = NGX_HTTP_OK; 215 | r->headers_out.content_length_n = captcha->size; 216 | r->headers_out.content_type = content_type; 217 | 218 | unsigned long bucket = r->start_sec - (r->start_sec % conf->bucket_duration); 219 | int bucket_size = 0; 220 | for (unsigned long i=1; isecret.len +r->connection->addr_text.len+conf->captcha_length + bucket_size +2 ) ); 224 | snprintf( 225 | (char *)input, 226 | ( conf->secret.len +r->connection->addr_text.len+conf->captcha_length + bucket_size +1 ), 227 | "%s%s%lu%s", 228 | conf->secret.data, r->connection->addr_text.data, bucket, captcha->message 229 | ); 230 | unsigned char output_sha512[64]; 231 | mySHA512((unsigned char *)input,output_sha512 ); 232 | 233 | 234 | unsigned char output_sha512_hex[129]; 235 | buf2hex(output_sha512, 64, output_sha512_hex); 236 | output_sha512_hex[128]='\0'; 237 | 238 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ CAPTCHA code] , OUTPUT2 =%s ff\n", (char *)input); 239 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ CAPTCHA code] , HASH2 =%s ff\n", (char *)output_sha512_hex); 240 | free(input); 241 | set_captcha_cookie(r,(u_char*)output_sha512_hex); 242 | ngx_http_send_header(r); 243 | 244 | ngx_buf_t *b; 245 | ngx_chain_t out; 246 | b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); 247 | 248 | out.buf = b; 249 | out.next = NULL; 250 | 251 | b->pos = captcha->buf; 252 | b->last = captcha->buf + captcha->size; 253 | b->memory = 1; 254 | b->last_buf = 1; 255 | 256 | ngx_http_output_filter(r, &out); 257 | ngx_http_finalize_request(r, 0); 258 | destroy_captcha(captcha); //destroy captcha 259 | return NGX_DONE; 260 | } 261 | 262 | 263 | 264 | static ngx_int_t ngx_http_captcha_handler(ngx_http_request_t *r) { 265 | 266 | ngx_http_captcha_loc_conf_t *conf = ngx_http_get_module_loc_conf(r, ngx_http_captcha_module); 267 | 268 | if (!conf->enabled) { 269 | return NGX_DECLINED; 270 | } 271 | 272 | //captcha image 273 | //to do: generate dynamic link for image 274 | if ( strncmp((char *)r->uri.data,"/captcha123",11) == 0){ 275 | return serve_captcha(r, conf); 276 | } 277 | 278 | //get cookies 279 | ngx_str_t captcha_code; 280 | ngx_str_t cookie_name = ngx_string("captcha_code"); 281 | int ret = get_cookie(r, &cookie_name, &captcha_code); 282 | 283 | ngx_str_t resp; 284 | ngx_str_t cookie_name2 = ngx_string("resp"); 285 | int ret2 = get_cookie(r, &cookie_name2, &resp); 286 | 287 | if (ret < 0 || ret2 <0 ) { 288 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ CAPTCHA code] , captcha_code/resp is not set"); 289 | return serve_HTML(r); 290 | } 291 | 292 | if (captcha_code.len != 128 || resp.len != conf->captcha_length ){ 293 | return serve_HTML(r); 294 | } 295 | 296 | /** 297 | create input string ( secret + IP + time +resp cookie ) 298 | */ 299 | unsigned long bucket = r->start_sec - (r->start_sec % conf->bucket_duration); 300 | int bucket_size = 0; 301 | for (unsigned long i=1; isecret.len +r->connection->addr_text.len+resp.len + bucket_size +1 ) ); 305 | snprintf( 306 | (char *)input, 307 | ( conf->secret.len +r->connection->addr_text.len+resp.len + bucket_size +1 ), 308 | "%s%s%lu%s", 309 | conf->secret.data, r->connection->addr_text.data, bucket, resp.data 310 | ); 311 | 312 | unsigned char output_sha512[64]; 313 | mySHA512((unsigned char *)input,output_sha512 ); 314 | 315 | unsigned char output_sha512_hex[129]; 316 | buf2hex(output_sha512, 64, output_sha512_hex); 317 | output_sha512_hex[128]='\0'; 318 | 319 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ CAPTCHA code] , input=%s ff\n", input); 320 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ CAPTCHA code] , response_len=%d ff\n", resp.len); 321 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ CAPTCHA code] , capctcha_code=%d ff\n", captcha_code.len); 322 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ CAPTCHA code] , sha512=%s ff\n", output_sha512_hex); 323 | 324 | free(input); 325 | 326 | if (strncmp( (char *)captcha_code.data, (char *)output_sha512_hex , SHA_LEN ) != 0){ 327 | return serve_HTML(r); 328 | } 329 | 330 | return NGX_DECLINED; 331 | } 332 | 333 | 334 | 335 | 336 | static ngx_int_t ngx_http_captcha(ngx_conf_t *cf) { 337 | 338 | ngx_http_handler_pt *h; 339 | ngx_http_core_main_conf_t *main_conf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 340 | 341 | h = ngx_array_push(&main_conf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers); 342 | if (h == NULL) { 343 | ngx_log_error(NGX_LOG_ERR, cf->log, 0, "null"); 344 | return NGX_ERROR; 345 | } 346 | *h = ngx_http_captcha_handler; 347 | return NGX_OK; 348 | } 349 | 350 | --------------------------------------------------------------------------------