Skip to content

Instantly share code, notes, and snippets.

@ngaranko
Created October 8, 2013 10:43
Show Gist options
  • Save ngaranko/6882858 to your computer and use it in GitHub Desktop.
Save ngaranko/6882858 to your computer and use it in GitHub Desktop.
CSRF token old
-module(boss_csrf_middleware).
-export([before_/3, after_/4]).
before_(Req, _SessionID, Info) ->
[CSRF_Token, NewToken] = get_csrf_token(Req),
case lists:member(Req:request_method(), ['GET', 'HEAD', 'OPTIONS', 'TRACE']) of
true -> accept_(Req, NewToken);
false ->
case proplists:is_defined(do_not_enforce_csrf_checks, Info) of
true -> accept_(Req, NewToken);
false ->
case check_referer(Req) of
false -> reject_(Req, NewToken, incorrect_referer);
true ->
pre_check_csrf_token(Req, CSRF_Token, NewToken)
end
end
end.
after_(_Req, _SessionID, Result, _Headers) ->
Token = proplists:get_value(csrftoken, Result),
{ok, [], [mochiweb_cookies:cookie(csrftoken, Token, [{path, "/"}, {max_age, boss_session:get_session_exp_time()}])]}.
pre_check_csrf_token(Req, CSRF_Token, NewToken) ->
%% Pre check CSRF token
case CSRF_Token =:= none of
true ->
reject_(Req, NewToken, no_csrf_cookie);
false ->
case Req:post_param("csrfmiddlewaretoken") of
undefined ->
%% No CSRF Token in POST, let's check HEADERS
case proplists:get_value(http_x_csrftoken, Req:headers()) of
undefined -> reject_(Req, NewToken, no_csrf_token);
HTTPToken ->
check_csrf_token(Req, HTTPToken, CSRF_Token, NewToken)
end;
PostToken ->
%% We have token, let's check it
check_csrf_token(Req, PostToken, CSRF_Token, NewToken)
end
end.
check_csrf_token(Req, PostToken, CSRF_Token, NewToken) ->
case PostToken =:= CSRF_Token of
true ->
accept_(Req, NewToken);
false ->
reject_(Req, NewToken, incorrect_csrf_token)
end.
get_csrf_token(Req) ->
case Req:cookie("csrftoken") of
undefined ->
%% Generate New
[none, get_random_string(12)];
Token ->
[Token, Token]
end.
get_random_string(Length) ->
get_random_string(Length, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789").
get_random_string(Length, AllowedChars) ->
lists:foldl(fun(_, Acc) ->
[lists:nth(random:uniform(length(AllowedChars)),
AllowedChars)]
++ Acc
end, [], lists:seq(1, Length)).
check_referer(Req) ->
%% Check referer, only on secure requests
case proplists:get_value(referer, Req:headers()) of
undefined ->
%%false;
true;
_Referer -> %% TODO: Finish referer check
true
end.
accept_(Req, Token) ->
UpdatedToken = case proplists:get_value("csrfmiddlewaretoken", Req:post_params(), undefined) of
undefined ->
Token; % Current token hasn't been used, let's reuse it.
_Otoher ->
get_random_string(12)
end,
{ok, [{csrftoken, UpdatedToken},
{csrf_input, csrf_input_(UpdatedToken)}]}.
reject_(_Req, _Token, Reason) ->
{error, Reason}.
csrf_input_(Token) ->
io_lib:format("<input type=\"hidden\" name=\"csrfmiddlewaretoken\" value=\"~s\" />", [Token]).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment