Sei sulla pagina 1di 16

(//docs.oracle.

com/en/)

SignIn(http://www.oracle.com/webapps/redirect/signon?nexturl=http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/dynamic.htm)

Home(/)/Database(/en/database/)/OracleDatabaseOnlineDocumentation11gRelease2(11.2)(../../index.htm)/
DatabaseAdministration(../../nav/portal_4.htm)

DatabasePL/SQLLanguageReference

7PL/SQLDynamicSQL
DynamicSQLisaprogrammingmethodologyforgeneratingandrunningSQLstatementsatruntime.
Itisusefulwhenwritinggeneralpurposeandflexibleprogramslikeadhocquerysystems,whenwriting
programsthatmustrundatabasedefinitionlanguage(DDL)statements,orwhenyoudonotknowat
compilationtimethefulltextofaSQLstatementorthenumberordatatypesofitsinputandoutput
variables.
PL/SQLprovidestwowaystowritedynamicSQL:

NativedynamicSQL,aPL/SQLlanguage(thatis,native)featureforbuildingandrunningdynamic
SQLstatements
DBMS_SQLpackage,anAPIforbuilding,running,anddescribingdynamicSQLstatements

NativedynamicSQLcodeiseasiertoreadandwritethanequivalentcodethatusestheDBMS_SQL
package,andrunsnoticeablyfaster(especiallywhenitcanbeoptimizedbythecompiler).However,to
writenativedynamicSQLcode,youmustknowatcompiletimethenumberanddatatypesoftheinput
andoutputvariablesofthedynamicSQLstatement.Ifyoudonotknowthisinformationatcompiletime,
youmustusetheDBMS_SQLpackage.
WhenyouneedboththeDBMS_SQLpackageandnativedynamicSQL,youcanswitchbetweenthem,
usingthe"DBMS_SQL.TO_REFCURSORFunction"(#BHCECGGF)and
"DBMS_SQL.TO_CURSOR_NUMBERFunction"(#BHCBJGEH).

Topics

WhenYouNeedDynamicSQL(#i12999)
NativeDynamicSQL(#i13130)
DBMS_SQLPackage(#BHCIBJBG)
SQLInjection(#CHDFCHHJ)

WhenYouNeedDynamicSQL
InPL/SQL,youneeddynamicSQLtorun:

SQLwhosetextisunknownatcompiletime
Forexample,aSELECTstatementthatincludesanidentifierthatisunknownatcompiletime(suchas
atablename)oraWHEREclauseinwhichthenumberofsubclausesisunknownatcompiletime.
SQLthatisnotsupportedasstaticSQL
Thatis,anySQLconstructnotincludedin"DescriptionofStaticSQL"(static.htm#i7112).

IfyoudonotneeddynamicSQL,usestaticSQL,whichhastheseadvantages:

SuccessfulcompilationverifiesthatstaticSQLstatementsreferencevaliddatabaseobjectsandthat
thenecessaryprivilegesareinplacetoaccessthoseobjects.
Successfulcompilationcreatesschemaobjectdependencies.
Forinformationaboutschemaobjectdependencies,seeOracleDatabaseAdvancedApplication
Developer'sGuide(../../appdev.112/e41502/adfns_dependencies.htm#ADFNS99967).

ForinformationaboutusingstaticSQLstatementswithPL/SQL,seeChapter6,"PL/SQLStaticSQL."
(static.htm#BABGEDAE)

NativeDynamicSQL
NativedynamicSQLprocessesmostdynamicSQLstatementswiththeEXECUTEIMMEDIATE
statement.
IfthedynamicSQLstatementisaSELECTstatementthatreturnsmultiplerows,nativedynamicSQL
givesyouthesechoices:

UsetheEXECUTEIMMEDIATEstatementwiththeBULKCOLLECTINTOclause.
UsetheOPENFOR,FETCH,andCLOSEstatements.

TheSQLcursorattributesworkthesamewayafternativedynamicSQLINSERT,UPDATE,DELETE,
MERGE,andsinglerowSELECTstatementsastheydofortheirstaticSQLcounterparts.Formore
informationaboutSQLcursorattributes,see"Cursors"(static.htm#BABDHAED).

Topics

EXECUTEIMMEDIATEStatement(#BHCEBBAI)
OPENFOR,FETCH,andCLOSEStatements(#i13057)
RepeatedPlaceholderNamesinDynamicSQLStatements(#BHCGEFCA)

EXECUTEIMMEDIATEStatement
TheEXECUTEIMMEDIATEstatementisthemeansbywhichnativedynamicSQLprocessesmost
dynamicSQLstatements.
IfthedynamicSQLstatementisselfcontained(thatis,ifithasnoplaceholdersforbindvariablesand
theonlyresultthatitcanpossiblyreturnisanerror),thentheEXECUTEIMMEDIATEstatementneedsno
clauses.
IfthedynamicSQLstatementincludesplaceholdersforbindvariables,eachplaceholdermusthavea
correspondingbindvariableintheappropriateclauseoftheEXECUTEIMMEDIATEstatement,asfollows:

IfthedynamicSQLstatementisaSELECTstatementthatcanreturnatmostonerow,putoutbind
variables(defines)intheINTOclauseandinbindvariablesintheUSINGclause.
IfthedynamicSQLstatementisaSELECTstatementthatcanreturnmultiplerows,putoutbind
variables(defines)intheBULKCOLLECTINTOclauseandinbindvariablesintheUSINGclause.
IfthedynamicSQLstatementisaDMLstatementwithoutaRETURNINGINTOclause,otherthan
SELECT,putallbindvariablesintheUSINGclause.
IfthedynamicSQLstatementisaDMLstatementwithaRETURNINGINTOclause,putinbind
variablesintheUSINGclauseandoutbindvariablesintheRETURNINGINTOclause.
IfthedynamicSQLstatementisananonymousPL/SQLblockoraCALLstatement,putallbind
variablesintheUSINGclause.
IfthedynamicSQLstatementinvokesasubprogram,ensurethat:

Everybindvariablethatcorrespondstoaplaceholderforasubprogramparameterhasthesame
parametermodeasthatsubprogramparameter(asinExample71(#CHDIEFCJ))andadatatype
thatiscompatiblewiththatofthesubprogramparameter.(Forinformationaboutcompatibledata
types,see"FormalandActualSubprogramParameters"(subprograms.htm#i4100).)
NobindvariablehasadatatypethatSQLdoesnotsupport(suchasBOOLEANinExample72
(#BHCEJIDC)).

TheUSINGclausecannotcontaintheliteralNULL.Toworkaroundthisrestriction,useanuninitialized
variablewhereyouwanttouseNULL,asinExample73(#BHCBIICB).
ForsyntaxdetailsoftheEXECUTEIMMEDIATEstatement,see"EXECUTEIMMEDIATEStatement"

ForsyntaxdetailsoftheEXECUTEIMMEDIATEstatement,see"EXECUTEIMMEDIATEStatement"
(executeimmediate_statement.htm#i33888).
Example71InvokingSubprogramfromDynamicPL/SQLBlock
SubprogramthatdynamicPL/SQLblockinvokes:CREATEORREPLACEPROCEDURE
create_dept(deptidINOUTNUMBER,dnameINVARCHAR2,mgridINNUMBER,locid
INNUMBER)ASBEGINdeptid:=departments_seq.NEXTVALINSERTINTOdepartments
(department_id,department_name,manager_id,location_id)VALUES(deptid,
dname,mgrid,locid)END/DECLAREplsql_blockVARCHAR2(500)new_deptid
NUMBER(4)new_dnameVARCHAR2(30):='Advertising'new_mgridNUMBER(6):=200
new_locidNUMBER(4):=1700BEGINDynamicPL/SQLblockinvokessubprogram:
plsql_block:='BEGINcreate_dept(:a,:b,:c,:d)END'/*Specifybind
variablesinUSINGclause.Specifymodeforfirstparameter.Modesofother
parametersarecorrectbydefault.*/EXECUTEIMMEDIATEplsql_blockUSINGIN
OUTnew_deptid,new_dname,new_mgrid,new_locidEND/

Example72UnsupportedDataTypeinNativeDynamicSQL
DECLAREdyn_stmtVARCHAR2(200)b1BOOLEANFUNCTIONf(xINTEGER)RETURN
BOOLEANASBEGINNULLENDfBEGINdyn_stmt:='BEGIN:b:=f(5)END'
EXECUTEIMMEDIATEdyn_stmtUSINGOUTb1END/

Result:
EXECUTEIMMEDIATEdyn_stmtUSINGOUTb1*ERRORatline15:ORA06550:line
15,column40:PLS00457:expressionshavetobeofSQLtypesORA06550:line
15,column3:PL/SQL:Statementignored

Example73UninitializedVariableRepresentsNULLinUSINGClause
CREATETABLEemployees_tempASSELECT*FROMEMPLOYEESDECLAREa_nullCHAR(1)
SettoNULLautomaticallyatruntimeBEGINEXECUTEIMMEDIATE'UPDATE
employees_tempSETcommission_pct=:x'USINGa_nullEND/

OPENFOR,FETCH,andCLOSEStatements
IfthedynamicSQLstatementrepresentsaSELECTstatementthatreturnsmultiplerows,youcan
processitwithnativedynamicSQLasfollows:

1. UseanOPENFORstatementtoassociateacursorvariablewiththedynamicSQLstatement.In
theUSINGclauseoftheOPENFORstatement,specifyabindvariableforeachplaceholderinthe
dynamicSQLstatement.
TheUSINGclausecannotcontaintheliteralNULL.Toworkaroundthisrestriction,usean
uninitializedvariablewhereyouwanttouseNULL,asinExample73(#BHCBIICB).
Forsyntaxdetails,see"OPENFORStatement"(openfor_statement.htm#i35231).

2. UsetheFETCHstatementtoretrieveresultsetrowsoneatatime,severalatatime,orallat
once.
Forsyntaxdetails,see"FETCHStatement"(fetch_statement.htm#i34221).
3. UsetheCLOSEstatementtoclosethecursorvariable.
Forsyntaxdetails,see"CLOSEStatement"(close_statement.htm#i32987).

Example74(#BHCFDIAI)listsallemployeeswhoaremanagers,retrievingresultsetrowsoneatatime.
Example74NativeDynamicSQLwithOPENFOR,FETCH,andCLOSEStatements
DECLARETYPEEmpCurTypISREFCURSORv_emp_cursorEmpCurTypemp_record
employees%ROWTYPEv_stmt_strVARCHAR2(200)v_e_jobemployees.job%TYPEBEGIN
DynamicSQLstatementwithplaceholder:v_stmt_str:='SELECT*FROM
employeesWHEREjob_id=:j'Opencursor&specifybindvariableinUSING
clause:OPENv_emp_cursorFORv_stmt_strUSING'MANAGER'Fetchrowsfrom
resultsetoneatatime:LOOPFETCHv_emp_cursorINTOemp_recordEXITWHEN
v_emp_cursor%NOTFOUNDENDLOOPClosecursor:CLOSEv_emp_cursorEND/

RepeatedPlaceholderNamesinDynamicSQLStatements
IfyourepeatplaceholdernamesindynamicSQLstatements,beawarethatthewayplaceholdersare
associatedwithbindvariablesdependsonthekindofdynamicSQLstatement.

Topics

DynamicSQLStatementisNotAnonymousBlockorCALLStatement(#BHCHIHEJ)
DynamicSQLStatementisAnonymousBlockorCALLStatement(#BHCHABFG)

DynamicSQLStatementisNotAnonymousBlockorCALLStatement
IfthedynamicSQLstatementdoesnotrepresentananonymousPL/SQLblockoraCALLstatement,
repetitionofplaceholdernamesisinsignificant.Placeholdersareassociatedwithbindvariablesinthe
USINGclausebyposition,notbyname.
Forexample,inthisdynamicSQLstatement,therepetitionofthename:xisinsignificant:
sql_stmt:='INSERTINTOpayrollVALUES(:x,:x,:y,:x)'

InthecorrespondingUSINGclause,youmustsupplyfourbindvariables.Theycanbedifferentfor
example:
EXECUTEIMMEDIATEsql_stmtUSINGa,b,c,d

TheprecedingEXECUTEIMMEDIATEstatementrunsthisSQLstatement:

TheprecedingEXECUTEIMMEDIATEstatementrunsthisSQLstatement:
INSERTINTOpayrollVALUES(a,b,c,d)

Toassociatethesamebindvariablewitheachoccurrenceof:x,youmustrepeatthatbindvariablefor
example:
EXECUTEIMMEDIATEsql_stmtUSINGa,a,b,a

TheprecedingEXECUTEIMMEDIATEstatementrunsthisSQLstatement:
INSERTINTOpayrollVALUES(a,a,b,a)

DynamicSQLStatementisAnonymousBlockorCALLStatement
IfthedynamicSQLstatementrepresentsananonymousPL/SQLblockoraCALLstatement,repetition
ofplaceholdernamesissignificant.Eachuniqueplaceholdernamemusthaveacorrespondingbind
variableintheUSINGclause.Ifyourepeataplaceholdername,youneednotrepeatitscorresponding
bindvariable.AllreferencestothatplaceholdernamecorrespondtoonebindvariableintheUSING
clause.
InExample75(#CHDFHEAG),allreferencestothefirstuniqueplaceholdername,:x,areassociatedwith
thefirstbindvariableintheUSINGclause,a,andtheseconduniqueplaceholdername,:y,is
associatedwiththesecondbindvariableintheUSINGclause,b.
Example75RepeatedPlaceholderNamesinDynamicPL/SQLBlock
CREATEPROCEDUREcalc_stats(wNUMBER,xNUMBER,yNUMBER,zNUMBER)ISBEGIN
DBMS_OUTPUT.PUT_LINE(w+x+y+z)END/DECLAREaNUMBER:=4bNUMBER:=
7plsql_blockVARCHAR2(100)BEGINplsql_block:='BEGINcalc_stats(:x,:x,
:y,:x)END'EXECUTEIMMEDIATEplsql_blockUSINGa,bcalc_stats(a,a,
b,a)END/

DBMS_SQLPackage
TheDBMS_SQLpackagedefinesanentitycalledaSQLcursornumber.BecausetheSQLcursor
numberisaPL/SQLinteger,youcanpassitacrosscallboundariesandstoreit.
YoumustusetheDBMS_SQLpackagetorunadynamicSQLstatementwhenyoudonotknoweitherof
theseuntilruntime:

SELECTlist

WhatplaceholdersinaSELECTorDMLstatementmustbebound

Inthesesituations,youmustusenativedynamicSQLinsteadoftheDBMS_SQLpackage:

ThedynamicSQLstatementretrievesrowsintorecords.
YouwanttousetheSQLcursorattribute%FOUND,%ISOPEN,%NOTFOUND,or%ROWCOUNTafterissuing
adynamicSQLstatementthatisanINSERT,UPDATE,DELETE,MERGE,orsinglerowSELECT
statement.

ForinformationaboutnativedynamicSQL,see"NativeDynamicSQL"(#i13130).
WhenyouneedboththeDBMS_SQLpackageandnativedynamicSQL,youcanswitchbetweenthem,
using:

DBMS_SQL.TO_REFCURSORFunction(#BHCECGGF)
DBMS_SQL.TO_CURSOR_NUMBERFunction(#BHCBJGEH)

Note:
YoucaninvokeDBMS_SQLsubprogramsremotely.

SeeAlso:
OracleDatabasePL/SQLPackagesandTypesReference(../../appdev.112/e40758/d_sql.htm#ARPLS058)
formoreinformationabouttheDBMS_SQLpackage,includinginstructionsforrunningadynamic
SQLstatementthathasanunknownnumberofinputoroutputvariables("Method4")

DBMS_SQL.TO_REFCURSORFunction
TheDBMS_SQL.TO_REFCURSORfunctionconvertsaSQLcursornumbertoaweakcursorvariable,which
youcanuseinnativedynamicSQLstatements.
BeforepassingaSQLcursornumbertotheDBMS_SQL.TO_REFCURSORfunction,youmustOPEN,PARSE,
andEXECUTEit(otherwiseanerroroccurs).
AfteryouconvertaSQLcursornumbertoaREFCURSORvariable,DBMS_SQLoperationscanaccessit
onlyastheREFCURSORvariable,notastheSQLcursornumber.Forexample,usingthe
DBMS_SQL.IS_OPENfunctiontoseeifaconvertedSQLcursornumberisstillopencausesanerror.
Example76(#g1777282)usestheDBMS_SQL.TO_REFCURSORfunctiontoswitchfromtheDBMS_SQL
packagetonativedynamicSQL.
Example76SwitchingfromDBMS_SQLPackagetoNativeDynamicSQL

CREATEORREPLACETYPEvc_arrayISTABLEOFVARCHAR2(200)/CREATEORREPLACE
TYPEnumlistISTABLEOFNUMBER/CREATEORREPLACEPROCEDUREdo_query_1(
placeholdervc_array,bindvarsvc_array,sql_stmtVARCHAR2)ISTYPEcurtypeIS
REFCURSORsrc_curcurtypecuridNUMBERbindnamesvc_arrayempnosnumlist
deptsnumlistretNUMBERisopenBOOLEANBEGINOpenSQLcursornumber:
curid:=DBMS_SQL.OPEN_CURSORParseSQLcursornumber:
DBMS_SQL.PARSE(curid,sql_stmt,DBMS_SQL.NATIVE)bindnames:=placeholder
Bindvariables:FORiIN1..bindnames.COUNTLOOP
DBMS_SQL.BIND_VARIABLE(curid,bindnames(i),bindvars(i))ENDLOOPRunSQL
cursornumber:ret:=DBMS_SQL.EXECUTE(curid)SwitchfromDBMS_SQLto
nativedynamicSQL:src_cur:=DBMS_SQL.TO_REFCURSOR(curid)FETCHsrc_curBULK
COLLECTINTOempnos,deptsThiswouldcauseanerrorbecausecuridwas
convertedtoaREFCURSOR:isopen:=DBMS_SQL.IS_OPEN(curid)CLOSEsrc_cur
END/

DBMS_SQL.TO_CURSOR_NUMBERFunction
TheDBMS_SQL.TO_CURSOR_NUMBERfunctionconvertsaREFCURSORvariable(eitherstrongorweak)to
aSQLcursornumber,whichyoucanpasstoDBMS_SQLsubprograms.
BeforepassingaREFCURSORvariabletotheDBMS_SQL.TO_CURSOR_NUMBERfunction,youmustOPEN
it.
AfteryouconvertaREFCURSORvariabletoaSQLcursornumber,nativedynamicSQLoperations
cannotaccessit.
Example77(#BHCHJBHJ)usestheDBMS_SQL.TO_CURSOR_NUMBERfunctiontoswitchfromnative
dynamicSQLtotheDBMS_SQLpackage.
Example77SwitchingfromNativeDynamicSQLtoDBMS_SQLPackage
CREATEORREPLACEPROCEDUREdo_query_2(sql_stmtVARCHAR2)ISTYPEcurtypeIS
REFCURSORsrc_curcurtypecuridNUMBERdesctabDBMS_SQL.DESC_TABcolcnt
NUMBERnamevarVARCHAR2(50)numvarNUMBERdatevarDATEempnoNUMBER:=100
BEGINsql_stmt:=SELECT...FROMemployeesWHEREemployee_id=:b1'
OpenREFCURSORvariable:OPENsrc_curFORsql_stmtUSINGempnoSwitchfrom
nativedynamicSQLtoDBMS_SQLpackage:curid:=
DBMS_SQL.TO_CURSOR_NUMBER(src_cur)DBMS_SQL.DESCRIBE_COLUMNS(curid,colcnt,
desctab)Definecolumns:FORiIN1..colcntLOOPIFdesctab(i).col_type=
2THENDBMS_SQL.DEFINE_COLUMN(curid,i,numvar)ELSIFdesctab(i).col_type=12
THENDBMS_SQL.DEFINE_COLUMN(curid,i,datevar)statementsELSE
DBMS_SQL.DEFINE_COLUMN(curid,i,namevar,50)ENDIFENDLOOPFetchrows
withDBMS_SQLpackage:WHILEDBMS_SQL.FETCH_ROWS(curid)>0LOOPFORiIN1..
colcntLOOPIF(desctab(i).col_type=1)THENDBMS_SQL.COLUMN_VALUE(curid,i,
namevar)ELSIF(desctab(i).col_type=2)THENDBMS_SQL.COLUMN_VALUE(curid,i,
numvar)ELSIF(desctab(i).col_type=12)THENDBMS_SQL.COLUMN_VALUE(curid,i,
datevar)statementsENDIFENDLOOPENDLOOP
DBMS_SQL.CLOSE_CURSOR(curid)END/

SQLInjection
SQLinjectionmaliciouslyexploitsapplicationsthatuseclientsupplieddatainSQLstatements,thereby
gainingunauthorizedaccesstoadatabasetoviewormanipulaterestricteddata.Thissectiondescribes
SQLinjectionvulnerabilitiesinPL/SQLandexplainshowtoguardagainstthem.
Totrytheexamplesinthistopic,connecttotheHRschemaandrunthestatementsinExample78
(#CHDBJCFF).
Example78SetupforSQLInjectionExamples
DROPTABLEsecret_recordsCREATETABLEsecret_records(user_nameVARCHAR2(9),
service_typeVARCHAR2(12),valueVARCHAR2(30),date_createdDATE)INSERTINTO
secret_records(user_name,service_type,value,date_created)VALUES('Andy',
'Waiter','ServedinneratCafePete',SYSDATE)INSERTINTOsecret_records(
user_name,service_type,value,date_created)VALUES('Chuck','Merger','Buy
companyXYZ',SYSDATE)

Topics

SQLInjectionTechniques(#BJEEBJAE)
GuardingAgainstSQLInjection(#BJECFFHD)

SQLInjectionTechniques
AllSQLinjectiontechniquesexploitasinglevulnerability:Stringinputisnotcorrectlyvalidatedandis
concatenatedintoadynamicSQLstatement.

Topics

StatementModification(#BJEBCDDH)
StatementInjection(#BJEJJDEG)
DataTypeConversion(#CHDDEBCJ)

StatementModification
StatementmodificationmeansdeliberatelyalteringadynamicSQLstatementsothatitrunsinaway
unintendedbytheapplicationdeveloper.Typically,theuserretrievesunauthorizeddatabychangingthe
WHEREclauseofaSELECTstatementorbyinsertingaUNIONALLclause.Theclassicexampleofthis
techniqueisbypassingpasswordauthenticationbymakingaWHEREclausealwaysTRUE.
Example79(#BJEJABIC)createsaprocedurethatisvulnerabletostatementmodificationandthen
invokesthatprocedurewithandwithoutstatementmodification.Withstatementmodification,the
procedurereturnsasupposedlysecretrecord.

Example79ProcedureVulnerabletoStatementModification
Createvulnerableprocedure:
CREATEORREPLACEPROCEDUREget_record(user_nameINVARCHAR2,service_typeIN
VARCHAR2,recOUTVARCHAR2)ISqueryVARCHAR2(4000)BEGINFollowingSELECT
statementisvulnerabletomodificationbecauseitusesconcatenationto
buildWHEREclause.query:='SELECTvalueFROMsecret_recordsWHERE
user_name='''||user_name||'''ANDservice_type='''||service_type||''''
DBMS_OUTPUT.PUT_LINE('Query:'||query)EXECUTEIMMEDIATEqueryINTOrec
DBMS_OUTPUT.PUT_LINE('Rec:'||rec)END/

DemonstrateprocedurewithoutSQLinjection:
SETSERVEROUTPUTONDECLARErecord_valueVARCHAR2(4000)BEGIN
get_record('Andy','Waiter',record_value)END/

Result:
Query:SELECTvalueFROMsecret_recordsWHEREuser_name='Andy'AND
service_type='Waiter'Rec:ServedinneratCafePete

Exampleofstatementmodification:
DECLARErecord_valueVARCHAR2(4000)BEGINget_record('Anybody''OR
service_type=''Merger''','Anything',record_value)END/

Result:
Query:SELECTvalueFROMsecret_recordsWHEREuser_name='Anybody'OR
service_type='Merger''ANDservice_type='Anything'Rec:BuycompanyXYZ
PL/SQLproceduresuccessfullycompleted.

StatementInjection
StatementinjectionmeansthatauserappendsoneormoreSQLstatementstoadynamicSQL
statement.AnonymousPL/SQLblocksarevulnerabletothistechnique.
Example710(#BJEHHAFF)createsaprocedurethatisvulnerabletostatementinjectionandthen
invokesthatprocedurewithandwithoutstatementinjection.Withstatementinjection,theprocedure
deletesthesupposedlysecretrecordexposedinExample79(#BJEJABIC).
Example710ProcedureVulnerabletoStatementInjection
Createvulnerableprocedure:

CREATEORREPLACEPROCEDUREp(user_nameINVARCHAR2,service_typeINVARCHAR2
)ISblock1VARCHAR2(4000)BEGINFollowingblockisvulnerabletostatement
injectionbecauseitisbuiltbyconcatenation.block1:='BEGIN
DBMS_OUTPUT.PUT_LINE(''user_name:'||user_name||''')'||
'DBMS_OUTPUT.PUT_LINE(''service_type:'||service_type||''')END'
DBMS_OUTPUT.PUT_LINE('Block1:'||block1)EXECUTEIMMEDIATEblock1END/

DemonstrateprocedurewithoutSQLinjection:
SETSERVEROUTPUTONBEGINp('Andy','Waiter')END/

Result:
Block1:BEGINDBMS_OUTPUT.PUT_LINE('user_name:Andy')
DBMS_OUTPUT.PUT_LINE('service_type:Waiter')ENDuser_name:Andy
service_type:Waiter

SQL*Plusformattingcommand:
COLUMNdate_createdFORMATA12

Query:
SELECT*FROMsecret_recordsORDERBYuser_name

Result:
USER_NAMESERVICE_TYPEVALUEDATE_CREATED
AndyWaiterServedinneratCafePete28APR10
ChuckMergerBuycompanyXYZ28APR10

Exampleofstatementmodification:
BEGINp('Anybody','Anything'')DELETEFROMsecret_recordsWHERE
service_type=INITCAP(''Merger')END/

Result:
Block1:BEGINDBMS_OUTPUT.PUT_LINE('user_name:Anybody')
DBMS_OUTPUT.PUT_LINE('service_type:Anything')DELETEFROMsecret_records
WHEREservice_type=INITCAP('Merger')ENDuser_name:Anybodyservice_type:
AnythingPL/SQLproceduresuccessfullycompleted.

Query:
SELECT*FROMsecret_records

Result:

USER_NAMESERVICE_TYPEVALUEDATE_CREATED
AndyWaiterServedinneratCafePete18MAR091
rowselected.

DataTypeConversion
AlessknownSQLinjectiontechniqueusesNLSsessionparameterstomodifyorinjectSQL
statements.
AdatetimeornumericvaluethatisconcatenatedintothetextofadynamicSQLstatementmustbe
convertedtotheVARCHAR2datatype.Theconversioncanbeeitherimplicit(whenthevalueisan
operandoftheconcatentationoperator)orexplicit(whenthevalueistheargumentoftheTO_CHAR
function).ThisdatatypeconversiondependsontheNLSsettingsofthedatabasesessionthatrunsthe
dynamicSQLstatement.Theconversionofdatetimevaluesusesformatmodelsspecifiedinthe
parametersNLS_DATE_FORMAT,NLS_TIMESTAMP_FORMAT,orNLS_TIMESTAMP_TZ_FORMAT,
dependingontheparticulardatetimedatatype.Theconversionofnumericvaluesappliesdecimaland
groupseparatorsspecifiedintheparameterNLS_NUMERIC_CHARACTERS.
Onedatetimeformatmodelis"text".Thetextiscopiedintotheconversionresult.Forexample,if
thevalueofNLS_DATE_FORMATis'"Month:"Month',theninJune,TO_CHAR(SYSDATE)returns
'Month:June'.ThedatetimeformatmodelcanbeabusedasshowninExample711(#CHDEIABG).
Example711ProcedureVulnerabletoSQLInjectionThroughDataTypeConversion
SELECT*FROMsecret_records

Result:
USER_NAMESERVICE_TYPEVALUEDATE_CREATE
AndyWaiterServedinneratCafePete28APR2010
ChuckMergerBuycompanyXYZ28APR2010

Createvulnerableprocedure:
ReturnrecordsnotolderthanamonthCREATEORREPLACEPROCEDURE
get_recent_record(user_nameINVARCHAR2,service_typeINVARCHAR2,recOUT
VARCHAR2)ISqueryVARCHAR2(4000)BEGIN/*FollowingSELECTstatementis
vulnerabletomodificationbecauseitusesconcatenationtobuildWHEREclause
andbecauseSYSDATEdependsonthevalueofNLS_DATE_FORMAT.*/query:=
'SELECTvalueFROMsecret_recordsWHEREuser_name='''||user_name||'''AND
service_type='''||service_type||'''ANDdate_created>'''||(SYSDATE30)
||''''DBMS_OUTPUT.PUT_LINE('Query:'||query)EXECUTEIMMEDIATEqueryINTO
recDBMS_OUTPUT.PUT_LINE('Rec:'||rec)END/

DemonstrateprocedurewithoutSQLinjection:
SETSERVEROUTPUTONALTERSESSIONSETNLS_DATE_FORMAT='DDMONYYYY'DECLARE
record_valueVARCHAR2(4000)BEGINget_recent_record('Andy','Waiter',
record_value)END/

Result:
Query:SELECTvalueFROMsecret_recordsWHEREuser_name='Andy'AND
service_type='Waiter'ANDdate_created>'29MAR2010'Rec:ServedinneratCafe
Pete

Exampleofstatementmodification:
ALTERSESSIONSETNLS_DATE_FORMAT='"''ORservice_type=''Merger"'DECLARE
record_valueVARCHAR2(4000)BEGINget_recent_record('Anybody','Anything',
record_value)END/

Result:
Query:SELECTvalueFROMsecret_recordsWHEREuser_name='Anybody'AND
service_type='Anything'ANDdate_created>''ORservice_type='Merger'Rec:Buy
companyXYZPL/SQLproceduresuccessfullycompleted.

GuardingAgainstSQLInjection
IfyouusedynamicSQLinyourPL/SQLapplications,youmustchecktheinputtexttoensurethatitis
exactlywhatyouexpected.Youcanusethefollowingtechniques:

BindVariables(#BJEDAHEE)
ValidationChecks(#BJEICDDJ)
ExplicitFormatModels(#CHDGICJH)

BindVariables
ThemosteffectivewaytomakeyourPL/SQLcodeinvulnerabletoSQLinjectionattacksistousebind
variables.Thedatabaseusesthevaluesofbindvariablesexclusivelyanddoesnotinterprettheir
contentsinanyway.(Bindvariablesalsoimproveperformance.)
TheprocedureinExample712(#BJEIJEBJ)isinvulnerabletoSQLinjectionbecauseitbuildsthe
dynamicSQLstatementwithbindvariables(notbyconcatenationasinthevulnerableprocedurein
Example79(#BJEJABIC)).Thesamebindingtechniquefixesthevulnerableprocedureshownin
Example710(#BJEHHAFF).
Example712BindVariablesGuardingAgainstSQLInjection
Createinvulnerableprocedure:
CREATEORREPLACEPROCEDUREget_record_2(user_nameINVARCHAR2,service_type
INVARCHAR2,recOUTVARCHAR2)ISqueryVARCHAR2(4000)BEGINquery:='SELECT
valueFROMsecret_recordsWHEREuser_name=:aANDservice_type=:b'
DBMS_OUTPUT.PUT_LINE('Query:'||query)EXECUTEIMMEDIATEqueryINTOrec
USINGuser_name,service_typeDBMS_OUTPUT.PUT_LINE('Rec:'||rec)END/

DemonstrateprocedurewithoutSQLinjection:
SETSERVEROUTPUTONDECLARErecord_valueVARCHAR2(4000)BEGIN
get_record_2('Andy','Waiter',record_value)END/

Result:
Query:SELECTvalueFROMsecret_recordsWHEREuser_name=:aANDservice_type=:b
Rec:ServedinneratCafePetePL/SQLproceduresuccessfullycompleted.

Attemptstatementmodification:
DECLARErecord_valueVARCHAR2(4000)BEGINget_record_2('Anybody''OR
service_type=''Merger''','Anything',record_value)END/

Result:
Query:SELECTvalueFROMsecret_recordsWHEREuser_name=:aANDservice_type=:b
DECLARE*ERRORatline1:ORA01403:nodatafoundORA06512:at
"HR.GET_RECORD_2",line14ORA06512:atline4

ValidationChecks
Alwayshaveyourprogramvalidateuserinputtoensurethatitiswhatisintended.Forexample,ifthe
userispassingadepartmentnumberforaDELETEstatement,checkthevalidityofthisdepartment
numberbyselectingfromthedepartmentstable.Similarly,ifauserentersthenameofatabletobe
deleted,checkthatthistableexistsbyselectingfromthestaticdatadictionaryviewALL_TABLES.

Caution:
Whencheckingthevalidityofausernameanditspassword,alwaysreturnthesameerror
regardlessofwhichitemisinvalid.Otherwise,amalicioususerwhoreceivestheerror
message"invalidpassword"butnot"invalidusername"(orthereverse)canrealizethathe
orshehasguessedoneofthesecorrectly.
Invalidationcheckingcode,thesubprogramsintheDBMS_ASSERTpackageareoftenuseful.For
example,youcanusetheDBMS_ASSERT.ENQUOTE_LITERALfunctiontoencloseastringliteralin
quotationmarks,asExample713(#CHDGJEGD)does.Thispreventsamalicioususerfrominjectingtext
betweenanopeningquotationmarkanditscorrespondingclosingquotationmark.

Caution:
AlthoughtheDBMS_ASSERTsubprogramsareusefulinvalidationcode,theydonotreplace
it.Forexample,aninputstringcanbeaqualifiedSQLname(verifiedby
DBMS_ASSERT.QUALIFIED_SQL_NAME)andstillbeafraudulentpassword.

SeeAlso:
OracleDatabasePL/SQLPackagesandTypesReference(../../appdev.112/e40758/d_assert.htm#ARPLS231)
forinformationaboutDBMS_ASSERTsubprograms
InExample713

,theprocedureraise_emp_salarychecksthevalidityofthecolumn

InExample713(#CHDGJEGD),theprocedureraise_emp_salarychecksthevalidityofthecolumn
namethatwaspassedtoitbeforeitupdatestheemployeestable,andthentheanonymousblock
invokestheprocedurefrombothadynamicPL/SQLblockandadynamicSQLstatement.
Example713ValidationChecksGuardingAgainstSQLInjection
CREATEORREPLACEPROCEDUREraise_emp_salary(column_valueNUMBER,emp_column
VARCHAR2,amountNUMBER)ISv_columnVARCHAR2(30)sql_stmtVARCHAR2(200)
BEGINCheckvalidityofcolumnnamethatwasgivenasinput:SELECT
column_nameINTOv_columnFROMUSER_TAB_COLSWHERETABLE_NAME='EMPLOYEES'AND
COLUMN_NAME=emp_columnsql_stmt:='UPDATEemployeesSETsalary=salary+
:1WHERE'||DBMS_ASSERT.ENQUOTE_NAME(v_column,FALSE)||'=:2'EXECUTE
IMMEDIATEsql_stmtUSINGamount,column_valueIfcolumnnameisvalid:IF
SQL%ROWCOUNT>0THENDBMS_OUTPUT.PUT_LINE('Salarieswereupdatedfor:'||
emp_column||'='||column_value)ENDIFIfcolumnnameisnotvalid:
EXCEPTIONWHENNO_DATA_FOUNDTHENDBMS_OUTPUT.PUT_LINE('InvalidColumn:'||
emp_column)ENDraise_emp_salary/DECLAREplsql_blockVARCHAR2(500)BEGIN
Invokeraise_emp_salaryfromadynamicPL/SQLblock:plsql_block:='BEGIN
raise_emp_salary(:cvalue,:cname,:amt)END'EXECUTEIMMEDIATEplsql_block
USING110,'DEPARTMENT_ID',10Invokeraise_emp_salaryfromadynamicSQL
statement:EXECUTEIMMEDIATE'BEGINraise_emp_salary(:cvalue,:cname,:amt)
END'USING112,'EMPLOYEE_ID',10END/

Result:
Salarieswereupdatedfor:DEPARTMENT_ID=110Salarieswereupdatedfor:
EMPLOYEE_ID=112

ExplicitFormatModels
IfyouusedatetimeandnumericvaluesthatareconcatenatedintothetextofaSQLorPL/SQL
statement,andyoucannotpassthemasbindvariables,convertthemtotextusingexplicitformat
modelsthatareindependentfromthevaluesoftheNLSparametersoftherunningsession.Ensurethat
theconvertedvalueshavetheformatofSQLdatetimeornumericliterals.Usingexplicitlocale
independentformatmodelstoconstructSQLisrecommendednotonlyfromasecurityperspective,but
alsotoensurethatthedynamicSQLstatementrunscorrectlyinanyglobalizationenvironment.
TheprocedureinExample714(#CHDFIIEF)isinvulnerabletoSQLinjectionbecauseitconvertsthe
datetimeparametervalue,SYSDATE30,toaVARCHAR2valueexplicitly,usingtheTO_CHARfunction
andalocaleindependentformatmodel(notimplicitly,asinthevulnerableprocedureinExample711
(#CHDEIABG)).
Example714ExplicitFormatModelsGuardingAgainstSQLInjection
Createinvulnerableprocedure:

ReturnrecordsnotolderthanamonthCREATEORREPLACEPROCEDURE
get_recent_record(user_nameINVARCHAR2,service_typeINVARCHAR2,recOUT
VARCHAR2)ISqueryVARCHAR2(4000)BEGIN/*FollowingSELECTstatementis
vulnerabletomodificationbecauseitusesconcatenationtobuildWHEREclause.
*/query:='SELECTvalueFROMsecret_recordsWHEREuser_name='''||user_name
||'''ANDservice_type='''||service_type||'''ANDdate_created>DATE'''
||TO_CHAR(SYSDATE30,'YYYYMMDD')||''''DBMS_OUTPUT.PUT_LINE('Query:'
||query)EXECUTEIMMEDIATEqueryINTOrecDBMS_OUTPUT.PUT_LINE('Rec:'||
rec)END/

Attemptstatementmodification:
ALTERSESSIONSETNLS_DATE_FORMAT='"''ORservice_type=''Merger"'DECLARE
record_valueVARCHAR2(4000)BEGINget_recent_record('Anybody','Anything',
record_value)END/

Result:
Query:SELECTvalueFROMsecret_recordsWHEREuser_name='Anybody'AND
service_type='Anything'ANDdate_created>DATE'20100329'DECLARE*ERRORat
line1:ORA01403:nodatafoundORA06512:at"SYS.GET_RECENT_RECORD",line21
ORA06512:atline4

Page14of99

(http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/static.htm)

(http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/subprograms.htm)

(http://www.oracle.com/us/legal/index.html)

ContactUs (http://www.oracle.com/us/corporate/contact/index.html)

TermsofUse(http://www.oracle.com/us/legal/terms/index.html)

(http://www.oracle.com/us/legal/privacy/index.html)

Copyright2015,Oracleand/oritsaffiliates.Allrightsreserved.

LegalNotices

YourPrivacyRights

AboutOracle(http://www.oracle.com/corporate/index.html)

(#)

Potrebbero piacerti anche