dc_assert_abort inferred the outcome from the status row. The assertion should
prove the service rejected its input, so it now reads the child's response and
requires a sasjsAbort object, and compares that object's MSG value with the
message the service is expected to return:
%mpe_assert_abort(desc=An invalid libds aborts the service,
outref=web1, msg=Invalid libds)
Renamed with the mpe_ prefix to match the other macro-level helpers. getdata
Test 4 asserted completion with the abort macro, which was the wrong tool; it
now checks the status row for state=completed directly.
142 lines
3.3 KiB
SAS
142 lines
3.3 KiB
SAS
/**
|
|
@file
|
|
@brief testing getrawdata service - input validation (security)
|
|
@details table must be a well-formed LIBREF.DATASET (the trailing
|
|
format-catalog suffix is permitted), filter must be an integer and
|
|
type one of the supported download types. An invalid value aborts
|
|
the service before any request content can execute. The abort is
|
|
asserted from the child job state: the payloads either resolve to a
|
|
real table when executed as macro code, or write a file outside the
|
|
WORK directory (verified by live probe) - so on the vulnerable
|
|
service the job completes, and only the validating service cancels
|
|
it. The assertion cannot pass against a service that does not
|
|
validate.
|
|
|
|
<h4> SAS Macros </h4>
|
|
@li mpe_assert_abort.sas
|
|
@li mp_assert.sas
|
|
@li dc_execute.sas
|
|
|
|
**/
|
|
|
|
%let _program=&appLoc/services/public/getrawdata;
|
|
|
|
/**
|
|
* Test 1 - macro content in table must abort the service
|
|
* (the payload resolves to a real table when executed as macro code)
|
|
*/
|
|
data work.params1;
|
|
length name $32 value $1000;
|
|
name='type';value='CSV';output;
|
|
name='table';value='%sysfunc(coalescec(&mpelib..MPE_X_TEST,))';output;
|
|
name='filter';value='0';output;
|
|
run;
|
|
|
|
%dc_execute(&_program,
|
|
viyacontext=&defaultcontext,
|
|
inputparams=work.params1,
|
|
outref=web1,
|
|
outstatus=work.ab1,
|
|
failfast=0,
|
|
viyaresult=WEBOUT_TXT
|
|
)
|
|
|
|
%mpe_assert_abort(
|
|
desc=Macro content in table aborts the service,
|
|
outref=web1,
|
|
msg=Invalid filter
|
|
)
|
|
|
|
/**
|
|
* Test 2 - sql injection in filter must abort the service
|
|
*/
|
|
data work.params2;
|
|
length name $32 value $1000;
|
|
name='type';value='CSV';output;
|
|
name='table';value="&dclib..MPE_X_TEST";output;
|
|
name='filter';value='0 or 1=1';output;
|
|
run;
|
|
|
|
%dc_execute(&_program,
|
|
viyacontext=&defaultcontext,
|
|
inputparams=work.params2,
|
|
outref=web2,
|
|
outstatus=work.ab2,
|
|
failfast=0,
|
|
viyaresult=WEBOUT_TXT
|
|
)
|
|
|
|
%mpe_assert_abort(
|
|
desc=SQL injection in filter aborts the service,
|
|
outref=web2,
|
|
msg=Invalid filter
|
|
)
|
|
|
|
/**
|
|
* Test 3 - path traversal in table must abort the service
|
|
* (verified by live probe: on a vulnerable service this writes
|
|
* ../SECPROBE.csv outside the WORK directory and completes)
|
|
*/
|
|
data work.params3;
|
|
length name $32 value $1000;
|
|
name='type';value='CSV';output;
|
|
name='table';value='../secprobe';output;
|
|
name='filter';value='0';output;
|
|
run;
|
|
|
|
%dc_execute(&_program,
|
|
viyacontext=&defaultcontext,
|
|
inputparams=work.params3,
|
|
outref=web3,
|
|
outstatus=work.ab3,
|
|
failfast=0,
|
|
viyaresult=WEBOUT_TXT
|
|
)
|
|
|
|
%mpe_assert_abort(
|
|
desc=Path traversal in table aborts the service,
|
|
outref=web3,
|
|
msg=Invalid filter
|
|
)
|
|
|
|
/**
|
|
* Test 4 - the valid request must still work (positive control)
|
|
*/
|
|
data work.params4;
|
|
length name $32 value $1000;
|
|
name='type';value='CSV';output;
|
|
name='table';value="&dclib..MPE_X_TEST";output;
|
|
name='filter';value='0';output;
|
|
run;
|
|
|
|
%dc_execute(&_program,
|
|
viyacontext=&defaultcontext,
|
|
inputparams=work.params4,
|
|
outref=web4,
|
|
viyaresult=WEBOUT_TXT
|
|
)
|
|
|
|
%let ok4=0;
|
|
data _null_;
|
|
infile web4;
|
|
input;
|
|
if _infile_=:'PRIMARY_KEY_FIELD' then do;
|
|
call symputx('ok4',1);
|
|
stop;
|
|
end;
|
|
run;
|
|
|
|
%mp_assert(
|
|
iftrue=(&ok4=1),
|
|
desc=Valid table request still returns data,
|
|
outds=work.test_results
|
|
)
|
|
|
|
/**
|
|
* dump results to the log for offline inspection
|
|
*/
|
|
data _null_;
|
|
set work.test_results;
|
|
putlog 'TEST_RESULT_LINE: ' test_result ' - ' test_description;
|
|
run;
|