#include bool set_xsrf_token(evapp_ctx *ctx, HDF *hdf) { struct evkeyvalq cookie; struct timeval tv; uint64_t id = 0; char token[21]; bool secure = true; TAILQ_INIT(&cookie); gettimeofday(&tv, NULL); if (!hdf) return false; // We just use high-res time and some pseudo randomness. id = (tv.tv_sec - random()); id <<= 31; id |= (tv.tv_usec - random()); snprintf(token, sizeof(token), "%llu", id); evhttp_add_header(&cookie, "token", token); /* Disable secure cookies when in debug mode */ secure = !evapp_get_debug_mode(ctx); /* Set this at the top level and give it a day. Since this * has to be paired with the post data, I could care less how * long it lives. */ // XXX: maybe we can do better? // if everything was per object likst // /vuln/view instead, we could! if (!set_cookie(ctx, &cookie, "/", NULL, 86400, secure)) { evhttp_clear_headers(&cookie); return false; } evhttp_clear_headers(&cookie); hdf_set_value(hdf, "token", token); response_cacheable(ctx, CACHE_NONE, 0); return true; } bool check_xsrf(evapp_ctx *ctx, char *token) { struct app_settings *settings; struct evkeyvalq cookie; const char *ctoken = NULL; assert(ctx && token); settings = evapp_get_state(ctx); if (!evapp_get_xsrf_protection(ctx)) return true; TAILQ_INIT(&cookie); // XXX: we should avoid double parsing this cookie... if (!token || !parse_cookie(ctx, &cookie)) { return false; } ctoken = evhttp_find_header(&cookie, "token"); if (!ctoken) { evhttp_clear_headers(&cookie); return false; } /* Check against the length of the cookie token as that shouldn't * be tampered with. If we checked against the query, a token of * length 1 could be supplied meaning an easy brute force. */ if (strncmp(ctoken, token, strlen(ctoken))) { evhttp_clear_headers(&cookie); return false; } evhttp_clear_headers(&cookie); return true; }