Add referrer check responder, harden sessions against cross-site scripting
parent
a687b58226
commit
935d7d4321
|
@ -53,7 +53,7 @@ TUPLE: action rest authorize init display validate submit ;
|
||||||
] with-exit-continuation ;
|
] with-exit-continuation ;
|
||||||
|
|
||||||
: validation-failed ( -- * )
|
: validation-failed ( -- * )
|
||||||
request get method>> "POST" = [ f ] [ <400> ] if exit-with ;
|
post-request? [ f ] [ <400> ] if exit-with ;
|
||||||
|
|
||||||
: (handle-post) ( action -- response )
|
: (handle-post) ( action -- response )
|
||||||
'[
|
'[
|
||||||
|
@ -70,12 +70,9 @@ TUPLE: action rest authorize init display validate submit ;
|
||||||
|
|
||||||
: revalidate-url-key "__u" ;
|
: revalidate-url-key "__u" ;
|
||||||
|
|
||||||
: check-url ( url -- ? )
|
|
||||||
request get url>>
|
|
||||||
[ [ protocol>> ] [ host>> ] [ port>> ] tri 3array ] bi@ = ;
|
|
||||||
|
|
||||||
: revalidate-url ( -- url/f )
|
: revalidate-url ( -- url/f )
|
||||||
revalidate-url-key param dup [ >url dup check-url swap and ] when ;
|
revalidate-url-key param
|
||||||
|
dup [ >url [ same-host? ] keep and ] when ;
|
||||||
|
|
||||||
: handle-post ( action -- response )
|
: handle-post ( action -- response )
|
||||||
'[
|
'[
|
||||||
|
|
|
@ -5,12 +5,19 @@ furnace.cache
|
||||||
furnace.asides
|
furnace.asides
|
||||||
furnace.flash
|
furnace.flash
|
||||||
furnace.sessions
|
furnace.sessions
|
||||||
|
furnace.referrer
|
||||||
furnace.db
|
furnace.db
|
||||||
furnace.auth.providers ;
|
furnace.auth.providers ;
|
||||||
IN: furnace.alloy
|
IN: furnace.alloy
|
||||||
|
|
||||||
: <alloy> ( responder db params -- responder' )
|
: <alloy> ( responder db params -- responder' )
|
||||||
[ <asides> <flash-scopes> <sessions> ] 2dip <db-persistence> ;
|
'[
|
||||||
|
<asides>
|
||||||
|
<flash-scopes>
|
||||||
|
<sessions>
|
||||||
|
, , <db-persistence>
|
||||||
|
<check-form-submissions>
|
||||||
|
] call ;
|
||||||
|
|
||||||
: state-classes { session flash-scope aside } ; inline
|
: state-classes { session flash-scope aside } ; inline
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ ERROR: end-aside-in-get-error ;
|
||||||
dup [ dup session>> session get id>> = [ drop f ] unless ] when ;
|
dup [ dup session>> session get id>> = [ drop f ] unless ] when ;
|
||||||
|
|
||||||
: end-aside* ( url id -- response )
|
: end-aside* ( url id -- response )
|
||||||
request get method>> "POST" = [ end-aside-in-get-error ] unless
|
post-request? [ end-aside-in-get-error ] unless
|
||||||
aside get-state [
|
aside get-state [
|
||||||
dup method>> {
|
dup method>> {
|
||||||
{ "GET" [ url>> <redirect> ] }
|
{ "GET" [ url>> <redirect> ] }
|
||||||
|
|
|
@ -84,6 +84,17 @@ M: object modify-form drop ;
|
||||||
] }
|
] }
|
||||||
} case ;
|
} case ;
|
||||||
|
|
||||||
|
: referrer ( -- referrer )
|
||||||
|
#! Typo is intentional, its in the HTTP spec!
|
||||||
|
"referer" request get header>> at >url ;
|
||||||
|
|
||||||
|
: user-agent ( -- user-agent )
|
||||||
|
"user-agent" request get header>> at "" or ;
|
||||||
|
|
||||||
|
: same-host? ( url -- ? )
|
||||||
|
request get url>>
|
||||||
|
[ [ protocol>> ] [ host>> ] [ port>> ] tri 3array ] bi@ = ;
|
||||||
|
|
||||||
SYMBOL: exit-continuation
|
SYMBOL: exit-continuation
|
||||||
|
|
||||||
: exit-with ( value -- )
|
: exit-with ( value -- )
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
USING: accessors kernel
|
||||||
|
http.server http.server.filters http.server.responses
|
||||||
|
furnace ;
|
||||||
|
IN: furnace.referrer
|
||||||
|
|
||||||
|
TUPLE: referrer-check < filter-responder quot ;
|
||||||
|
|
||||||
|
C: <referrer-check> referrer-check
|
||||||
|
|
||||||
|
M: referrer-check call-responder*
|
||||||
|
referrer over quot>> call
|
||||||
|
[ call-next-method ]
|
||||||
|
[ 2drop 403 "Bad referrer" <trivial-response> ] if ;
|
||||||
|
|
||||||
|
: <check-form-submissions> ( responder -- responder' )
|
||||||
|
[ same-host? post-request? not or ] <referrer-check> ;
|
|
@ -2,14 +2,14 @@
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: assocs kernel math.intervals math.parser namespaces
|
USING: assocs kernel math.intervals math.parser namespaces
|
||||||
random accessors quotations hashtables sequences continuations
|
random accessors quotations hashtables sequences continuations
|
||||||
fry calendar combinators destructors alarms
|
fry calendar combinators destructors alarms io.server
|
||||||
db db.tuples db.types
|
db db.tuples db.types
|
||||||
http http.server http.server.dispatchers http.server.filters
|
http http.server http.server.dispatchers http.server.filters
|
||||||
html.elements
|
html.elements
|
||||||
furnace furnace.cache ;
|
furnace furnace.cache ;
|
||||||
IN: furnace.sessions
|
IN: furnace.sessions
|
||||||
|
|
||||||
TUPLE: session < server-state uid namespace changed? ;
|
TUPLE: session < server-state uid namespace user-agent client changed? ;
|
||||||
|
|
||||||
: <session> ( id -- session )
|
: <session> ( id -- session )
|
||||||
session new-server-state ;
|
session new-server-state ;
|
||||||
|
@ -18,6 +18,8 @@ session "SESSIONS"
|
||||||
{
|
{
|
||||||
{ "uid" "UID" { VARCHAR 255 } }
|
{ "uid" "UID" { VARCHAR 255 } }
|
||||||
{ "namespace" "NAMESPACE" FACTOR-BLOB +not-null+ }
|
{ "namespace" "NAMESPACE" FACTOR-BLOB +not-null+ }
|
||||||
|
{ "user-agent" "USER_AGENT" TEXT +not-null+ }
|
||||||
|
{ "client" "CLIENT" TEXT +not-null+ }
|
||||||
} define-persistent
|
} define-persistent
|
||||||
|
|
||||||
: get-session ( id -- session )
|
: get-session ( id -- session )
|
||||||
|
@ -31,10 +33,11 @@ M: dispatcher init-session* default>> init-session* ;
|
||||||
|
|
||||||
M: filter-responder init-session* responder>> init-session* ;
|
M: filter-responder init-session* responder>> init-session* ;
|
||||||
|
|
||||||
TUPLE: sessions < filter-responder timeout domain ;
|
TUPLE: sessions < server-state-manager domain verify? ;
|
||||||
|
|
||||||
: <sessions> ( responder -- responder' )
|
: <sessions> ( responder -- responder' )
|
||||||
sessions new-server-state-manager ;
|
sessions new-server-state-manager
|
||||||
|
t >>verify? ;
|
||||||
|
|
||||||
: (session-changed) ( session -- )
|
: (session-changed) ( session -- )
|
||||||
t >>changed? drop ;
|
t >>changed? drop ;
|
||||||
|
@ -66,9 +69,13 @@ TUPLE: sessions < filter-responder timeout domain ;
|
||||||
: touch-session ( session -- )
|
: touch-session ( session -- )
|
||||||
sessions get touch-state ;
|
sessions get touch-state ;
|
||||||
|
|
||||||
|
: remote-host ( -- string ) remote-address get host>> ;
|
||||||
|
|
||||||
: empty-session ( -- session )
|
: empty-session ( -- session )
|
||||||
f <session>
|
f <session>
|
||||||
H{ } clone >>namespace
|
H{ } clone >>namespace
|
||||||
|
remote-host >>client
|
||||||
|
user-agent >>user-agent
|
||||||
dup touch-session ;
|
dup touch-session ;
|
||||||
|
|
||||||
: begin-session ( -- session )
|
: begin-session ( -- session )
|
||||||
|
@ -107,8 +114,18 @@ M: session-saver dispose
|
||||||
{ "POST" [ post-session-id ] }
|
{ "POST" [ post-session-id ] }
|
||||||
} case ;
|
} case ;
|
||||||
|
|
||||||
|
: verify-session ( session -- session )
|
||||||
|
sessions get verify?>> [
|
||||||
|
dup [
|
||||||
|
dup
|
||||||
|
[ client>> remote-host = ]
|
||||||
|
[ user-agent>> user-agent = ]
|
||||||
|
bi and [ drop f ] unless
|
||||||
|
] when
|
||||||
|
] when ;
|
||||||
|
|
||||||
: request-session ( -- session/f )
|
: request-session ( -- session/f )
|
||||||
request-session-id get-session ;
|
request-session-id get-session verify-session ;
|
||||||
|
|
||||||
: <session-cookie> ( id -- cookie )
|
: <session-cookie> ( id -- cookie )
|
||||||
session-id-key <cookie>
|
session-id-key <cookie>
|
||||||
|
|
|
@ -269,7 +269,7 @@ SYMBOL: a
|
||||||
! Test flash scope
|
! Test flash scope
|
||||||
[ "xyz" ] [
|
[ "xyz" ] [
|
||||||
H{ { "a" "xyz" } { "__u" "http://localhost:1237/" } } "session-id" get session-id-key associate assoc-union
|
H{ { "a" "xyz" } { "__u" "http://localhost:1237/" } } "session-id" get session-id-key associate assoc-union
|
||||||
"http://localhost:1237/" <post-request> "cookies" get >>cookies B http-request nip test-a
|
"http://localhost:1237/" <post-request> "cookies" get >>cookies http-request nip test-a
|
||||||
] unit-test
|
] unit-test
|
||||||
|
|
||||||
[ 4 ] [ a get-global ] unit-test
|
[ 4 ] [ a get-global ] unit-test
|
||||||
|
|
|
@ -5,8 +5,6 @@ combinators arrays io.launcher io http.server.static http.server
|
||||||
http accessors sequences strings math.parser fry urls ;
|
http accessors sequences strings math.parser fry urls ;
|
||||||
IN: http.server.cgi
|
IN: http.server.cgi
|
||||||
|
|
||||||
: post? ( -- ? ) request get method>> "POST" = ;
|
|
||||||
|
|
||||||
: cgi-variables ( script-path -- assoc )
|
: cgi-variables ( script-path -- assoc )
|
||||||
#! This needs some work.
|
#! This needs some work.
|
||||||
[
|
[
|
||||||
|
@ -34,7 +32,7 @@ IN: http.server.cgi
|
||||||
request get "user-agent" header "HTTP_USER_AGENT" set
|
request get "user-agent" header "HTTP_USER_AGENT" set
|
||||||
request get "accept" header "HTTP_ACCEPT" set
|
request get "accept" header "HTTP_ACCEPT" set
|
||||||
|
|
||||||
post? [
|
post-request? [
|
||||||
request get post-data>> raw>>
|
request get post-data>> raw>>
|
||||||
[ "CONTENT_TYPE" set ]
|
[ "CONTENT_TYPE" set ]
|
||||||
[ length number>string "CONTENT_LENGTH" set ]
|
[ length number>string "CONTENT_LENGTH" set ]
|
||||||
|
@ -53,7 +51,7 @@ IN: http.server.cgi
|
||||||
"CGI output follows" >>message
|
"CGI output follows" >>message
|
||||||
swap '[
|
swap '[
|
||||||
, output-stream get swap <cgi-process> <process-stream> [
|
, output-stream get swap <cgi-process> <process-stream> [
|
||||||
post? [ request get post-data>> raw>> write flush ] when
|
post-request? [ request get post-data>> raw>> write flush ] when
|
||||||
input-stream get swap (stream-copy)
|
input-stream get swap (stream-copy)
|
||||||
] with-stream
|
] with-stream
|
||||||
] >>body ;
|
] >>body ;
|
||||||
|
|
|
@ -20,6 +20,8 @@ html.elements
|
||||||
html.streams ;
|
html.streams ;
|
||||||
IN: http.server
|
IN: http.server
|
||||||
|
|
||||||
|
: post-request? ( -- ? ) request get method>> "POST" = ;
|
||||||
|
|
||||||
SYMBOL: responder-nesting
|
SYMBOL: responder-nesting
|
||||||
|
|
||||||
SYMBOL: main-responder
|
SYMBOL: main-responder
|
||||||
|
|
|
@ -135,6 +135,8 @@ PRIVATE>
|
||||||
|
|
||||||
GENERIC: >url ( obj -- url )
|
GENERIC: >url ( obj -- url )
|
||||||
|
|
||||||
|
M: f >url drop <url> ;
|
||||||
|
|
||||||
M: url >url ;
|
M: url >url ;
|
||||||
|
|
||||||
M: string >url
|
M: string >url
|
||||||
|
|
|
@ -61,9 +61,7 @@ TUPLE: factor-website < dispatcher ;
|
||||||
: init-factor-website ( -- )
|
: init-factor-website ( -- )
|
||||||
"factorcode.org" 25 <inet> smtp-server set-global
|
"factorcode.org" 25 <inet> smtp-server set-global
|
||||||
"todo@factorcode.org" lost-password-from set-global
|
"todo@factorcode.org" lost-password-from set-global
|
||||||
|
|
||||||
init-factor-db
|
init-factor-db
|
||||||
|
|
||||||
<factor-website> main-responder set-global ;
|
<factor-website> main-responder set-global ;
|
||||||
|
|
||||||
: start-factor-website ( -- )
|
: start-factor-website ( -- )
|
||||||
|
|
|
@ -39,8 +39,6 @@ TUPLE: article title revision ;
|
||||||
|
|
||||||
article "ARTICLES" {
|
article "ARTICLES" {
|
||||||
{ "title" "TITLE" { VARCHAR 256 } +not-null+ +user-assigned-id+ }
|
{ "title" "TITLE" { VARCHAR 256 } +not-null+ +user-assigned-id+ }
|
||||||
! { "AUTHOR" INTEGER +not-null+ } ! uid
|
|
||||||
! { "PROTECTED" BOOLEAN +not-null+ }
|
|
||||||
{ "revision" "REVISION" INTEGER +not-null+ } ! revision id
|
{ "revision" "REVISION" INTEGER +not-null+ } ! revision id
|
||||||
} define-persistent
|
} define-persistent
|
||||||
|
|
||||||
|
@ -111,14 +109,17 @@ M: revision feed-entry-url id>> revision-url ;
|
||||||
|
|
||||||
{ wiki "view" } >>template ;
|
{ wiki "view" } >>template ;
|
||||||
|
|
||||||
|
: amend-article ( revision article -- )
|
||||||
|
swap id>> >>revision update-tuple ;
|
||||||
|
|
||||||
|
: add-article ( revision -- )
|
||||||
|
[ title>> ] [ id>> ] bi article boa insert-tuple ;
|
||||||
|
|
||||||
: add-revision ( revision -- )
|
: add-revision ( revision -- )
|
||||||
[ insert-tuple ]
|
[ insert-tuple ]
|
||||||
[
|
[
|
||||||
dup title>> <article> select-tuple [
|
dup title>> <article> select-tuple
|
||||||
swap id>> >>revision update-tuple
|
[ amend-article ] [ add-article ] if*
|
||||||
] [
|
|
||||||
[ title>> ] [ id>> ] bi article boa insert-tuple
|
|
||||||
] if*
|
|
||||||
] bi ;
|
] bi ;
|
||||||
|
|
||||||
: <edit-article-action> ( -- action )
|
: <edit-article-action> ( -- action )
|
||||||
|
|
Loading…
Reference in New Issue