Attacco intrusivo nel codice SQLSQL Injection

In un attacco SQL injection il malware viene inserito in stringhe successivamente passate un'istanza di SQL Server per l'analisi e l'esecuzione.SQL injection is an attack in which malicious code is inserted into strings that are later passed to an instance of SQL Server for parsing and execution. Per la prevenzione degli attacchi di questo tipo è necessario esaminare tutte le procedure che creano istruzioni SQL perché SQL Server esegue tutte le query sintatticamente valide che riceve.Any procedure that constructs SQL statements should be reviewed for injection vulnerabilities because SQL Server will execute all syntactically valid queries that it receives. Anche i dati con parametri possono essere modificati da un utente malintenzionato abile e determinato.Even parameterized data can be manipulated by a skilled and determined attacker.

Come funziona un attacco SQL injectionHow SQL Injection Works

La forma principale di un attacco intrusivo nel codice SQL consiste nell'inserimento diretto di codice in variabili di input utente concatenate a comandi SQL ed eseguite.The primary form of SQL injection consists of direct insertion of code into user-input variables that are concatenated with SQL commands and executed. Una forma meno diretta di attacco consiste nell'inserimento di malware in stringhe destinate all'archiviazione in una tabella o come metadati.A less direct attack injects malicious code into strings that are destined for storage in a table or as metadata. Quando le stringhe archiviate vengono successivamente concatenate in un comando SQL dinamico, il codice dannoso viene eseguito.When the stored strings are subsequently concatenated into a dynamic SQL command, the malicious code is executed.

Il processo di intrusione termina prematuramente una stringa di testo e aggiunge un nuovo comando.The injection process works by prematurely terminating a text string and appending a new command. Poiché prima che venga eseguito è possibile che al comando inserito vengano aggiunte ulteriori stringhe, l'utente malintenzionato termina la stringa inserita con un contrassegno di commento "--".Because the inserted command may have additional strings appended to it before it is executed, the malefactor terminates the injected string with a comment mark "--". Al momento del'esecuzione, il testo successivo al segno di commento viene ignorato.Subsequent text is ignored at execution time.

Nello script seguente viene illustrata una semplice intrusione nel codice SQL.The following script shows a simple SQL injection. Nello script viene compilata una query SQL tramite concatenazione di stringhe hardcoded a una stringa immessa dall'utente:The script builds an SQL query by concatenating hard-coded strings together with a string entered by the user:

var Shipcity;  
ShipCity = Request.form ("ShipCity");  
var sql = "select * from OrdersTable where ShipCity = '" + ShipCity + "'";  

L'utente riceve la richiesta di immettere il nome di una città.The user is prompted to enter the name of a city. Se l'utente immette Redmond, la query assemblata dallo script sarà simile alla seguente:If she enters Redmond, the query assembled by the script looks similar to the following:

SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond'  

Si supponga, tuttavia, che l'utente immetta la stringa seguente:However, assume that the user enters the following:

Redmond'; drop table OrdersTable--  

In questo caso, la query assemblata dallo script sarà la seguente:In this case, the following query is assembled by the script:

SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond';drop table OrdersTable--'  

Il punto e virgola (;) indica la fine di una query e l'inizio di un'altra.The semicolon (;) denotes the end of one query and the start of another. Il doppio trattino (--) indica che il resto della riga corrente è un commento che deve essere ignorato.The double hyphen (--) indicates that the rest of the current line is a comment and should be ignored. Se il codice modificato è sintatticamente corretto, verrà eseguito dal server.If the modified code is syntactically correct, it will be executed by the server. Quando SQL ServerSQL Server elabora questa istruzione, SQL ServerSQL Server seleziona prima tutti i record in OrdersTable in cui ShipCity è Redmond,When SQL ServerSQL Server processes this statement, SQL ServerSQL Server will first select all records in OrdersTable where ShipCity is Redmond. quindi SQL ServerSQL Server rimuove OrdersTable.Then, SQL ServerSQL Server will drop OrdersTable.

Se il codice SQL inserito è sintatticamente corretto, le manomissioni non possono essere rilevate a livello di programmazione.As long as injected SQL code is syntactically correct, tampering cannot be detected programmatically. È pertanto necessario convalidare tutti gli input utente e rivedere attentamente il codice per l'esecuzione dei comandi SQL generati nel server in uso.Therefore, you must validate all user input and carefully review code that executes constructed SQL commands in the server that you are using. Nelle sezioni seguenti di questo argomento vengono illustrate le procedure consigliate relative al codice.Coding best practices are described in the following sections in this topic.

Convalidare tutti gli inputValidate All Input

Convalidare sempre gli input utente testando tipo, lunghezza, formato e intervallo.Always validate user input by testing type, length, format, and range. Durante l'implementazione di precauzioni contro input dannosi, valutare gli scenari di distribuzione e l'architettura dell'applicazione in uso.When you are implementing precautions against malicious input, consider the architecture and deployment scenarios of your application. È importante ricordare che i programmi destinati all'esecuzione in un ambiente sicuro possono essere copiati in un ambiente non sicuro.Remember that programs designed to run in a secure environment can be copied to an nonsecure environment. I suggerimenti seguenti vanno considerati procedure consigliate:The following suggestions should be considered best practices:

  • Non basarsi su presupposti relativi a dimensioni, tipo o contenuto dei dati ricevuti dall'applicazione.Make no assumptions about the size, type, or content of the data that is received by your application. È ad esempio possibile valutare:For example, you should make the following evaluation:

    • Il comportamento dell'applicazione se un utente immette volontariamente o per errore un file MPEG da 10 MB nel punto in cui è previsto un codice postale.How will your application behave if an errant or malicious user enters a 10-megabyte MPEG file where your application expects a postal code?

    • Il comportamento dell'applicazione se un'istruzione DROP TABLE viene incorporata in un campo di testo.How will your application behave if a DROP TABLE statement is embedded in a text field?

  • Testare le dimensioni e il tipo di dati dell'input e imporre limiti appropriati.Test the size and data type of input and enforce appropriate limits. In questo modo è possibile impedire intenzionali sovraccarichi del buffer.This can help prevent deliberate buffer overruns.

  • Testare il contenuto delle variabili stringa e accettare solo i valori previsti.Test the content of string variables and accept only expected values. Rifiutare voci contenenti dati binari, sequenze di escape e caratteri di commento.Reject entries that contain binary data, escape sequences, and comment characters. Ciò consente di evitare l'attacco intrusivo nel codice script e può fornire protezione da alcuni exploit basati sul sovraccarico del buffer.This can help prevent script injection and can protect against some buffer overrun exploits.

  • Quando si utilizzano documenti XML, convalidare tutti i dati in base al relativo schema man mano che vengono immessi.When you are working with XML documents, validate all data against its schema as it is entered.

  • Non compilare mai istruzioni Transact-SQLTransact-SQL direttamente dall'input utente.Never build Transact-SQLTransact-SQL statements directly from user input.

  • Utilizzare stored procedure per la convalida dell'input utente.Use stored procedures to validate user input.

  • In ambienti multilivello è necessario convalidare tutti i dati prima di consentirne l'inserimento in aree considerate attendibili.In multitiered environments, all data should be validated before admission to the trusted zone. I dati che non superano il processo di convalida devono essere rifiutati e un errore deve essere restituito al livello precedente.Data that does not pass the validation process should be rejected and an error should be returned to the previous tier.

  • Implementare più livelli di convalida.Implement multiple layers of validation. Le precauzioni possono risultare inefficaci nella difesa da utenti malintenzionati determinati.Precautions you take against casually malicious users may be ineffective against determined attackers. Una procedura consigliata consiste nel convalidare l'input nell'interfaccia utente e in tutti i successivi punti in cui l'input oltrepassa il limite di un'area attendibile.A better practice is to validate input in the user interface and at all subsequent points where it crosses a trust boundary.
    Ad esempio, la convalida dei dati in un'applicazione sul lato client può impedire i semplici attacchi intrusivi nel codice script.For example, data validation in a client-side application can prevent simple script injection. Se, tuttavia, al livello successivo si presuppone che il relativo input sia già stato convalidato, l'utente malintenzionato in grado di ignorare un client potrà accedere in modo illimitato a un sistema.However, if the next tier assumes that its input has already been validated, any malicious user who can bypass a client can have unrestricted access to a system.

  • Non eseguire mai la concatenazione di input utente non convalidato.Never concatenate user input that is not validated. La concatenazione delle stringhe è il punto di ingresso principale per l'attacco intrusivo nel codice script.String concatenation is the primary point of entry for script injection.

  • Non accettare le stringhe seguenti in campi da cui è possibile creare nomi di file: AUX, CLOCK$, da COM1 a COM8, CON, CONFIG$, da LPT1 a LPT8, NUL e PRN.Do not accept the following strings in fields from which file names can be constructed: AUX, CLOCK$, COM1 through COM8, CON, CONFIG$, LPT1 through LPT8, NUL, and PRN.

    Quando possibile, rifiutare l'input contenente i caratteri seguenti.When you can, reject input that contains the following characters.

Carattere di inputInput character Significato in Transact-SQLMeaning in Transact-SQL
;; Delimitatore di queryQuery delimiter.
'' Delimitatore di stringhe di dati di tipo carattereCharacter data string delimiter.
-- Delimitatore di stringhe di dati di tipo carattereCharacter data string delimiter.
,.
/\* ... *//\* ... */ Delimitatori di commento.Comment delimiters. Il testo compreso fra /\* e */ non viene valutato dal server.Text between /\* and */ is not evaluated by the server.
xp_xp_ Usato all'inizio del nome delle stored procedure estese di catalogo come xp_cmdshell.Used at the start of the name of catalog-extended stored procedures, such as xp_cmdshell.

Utilizzo di parametri SQL type safeUse Type-Safe SQL Parameters

La raccolta Parameters in SQL ServerSQL Server implementa il controllo del tipo e la convalida della lunghezza.The Parameters collection in SQL ServerSQL Server provides type checking and length validation. Se si usa la raccolta Parameters , l'input viene interpretato come valore letterale e non come codice eseguibile.If you use the Parameters collection, input is treated as a literal value instead of as executable code. Un ulteriore vantaggio dell'utilizzo della raccolta Parameters consiste nella possibilità di applicare controlli sul tipo e sulla lunghezza.An additional benefit of using the Parameters collection is that you can enforce type and length checks. I valori non compresi nell'intervallo generano un'eccezione.Values outside the range will trigger an exception. Nel frammento di codice seguente viene illustrato l'utilizzo della raccolta Parameters :The following code fragment shows using the Parameters collection:

SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", conn);  
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;  
SqlParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id",  
     SqlDbType.VarChar, 11);  
parm.Value = Login.Text;  

In questo esempio il parametro @au_id viene interpretato come valore letterale e non come codice eseguibile.In this example, the @au_id parameter is treated as a literal value instead of as executable code. Vengono controllati il tipo e la lunghezza del valore.This value is checked for type and length. Se il valore di @au_id non è conforme ai vincoli di tipo e lunghezza specificati, viene generata un'eccezione.If the value of @au_id does not comply with the specified type and length constraints, an exception will be thrown.

Utilizzo di input con parametri nelle stored procedureUse Parameterized Input with Stored Procedures

Le stored procedure sono vulnerabili all'attacco intrusivo nel codice SQL se utilizzano input non filtrato.Stored procedures may be susceptible to SQL injection if they use unfiltered input. Ad esempio, il codice seguente è vulnerabile:For example, the following code is vulnerable:

SqlDataAdapter myCommand =   
new SqlDataAdapter("LoginStoredProcedure '" +   
                               Login.Text + "'", conn);  

Se si utilizzano stored procedure è opportuno utilizzare come input solo parametri.If you use stored procedures, you should use parameters as their input.

Utilizzo dell'insieme Parameters nelle istruzioni SQL dinamicheUse the Parameters Collection with Dynamic SQL

Se non si possono usare stored procedure, è comunque possibile usare parametri, come mostrato nell'esempio di codice seguente:If you cannot use stored procedures, you can still use parameters, as shown in the following code example.

SqlDataAdapter myCommand = new SqlDataAdapter(  
"SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", conn);  
SQLParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id",   
                        SqlDbType.VarChar, 11);  
Parm.Value = Login.Text;  

Filtraggio dell'inputFiltering Input

È anche possibile filtrare l'input per proteggersi da attacchi intrusivi nel codice SQL tramite la rimozione di caratteri di escape.Filtering input may also be helpful in protecting against SQL injection by removing escape characters. Dato il numero elevato di caratteri che potrebbero causare problemi, non è tuttavia possibile considerare affidabile questo metodo di difesa.However, because of the large number of characters that may pose problems, this is not a reliable defense. Nell'esempio seguente viene eseguita la ricerca del delimitatore di stringhe di caratteri.The following example searches for the character string delimiter.

private string SafeSqlLiteral(string inputSQL)  
{  
  return inputSQL.Replace("'", "''");  
}  

Clausole LIKELIKE Clauses

Si noti che se si usa una clausola LIKE sarà comunque necessario usare caratteri di escape per i caratteri jolly:Note that if you are using a LIKE clause, wildcard characters still must be escaped:

s = s.Replace("[", "[[]");  
s = s.Replace("%", "[%]");  
s = s.Replace("_", "[_]");  

Revisione del codice per attacchi intrusivi nel codice SQLReviewing Code for SQL Injection

È necessario rivedere tutto il codice che chiama EXECUTE, EXECo sp_executesql.You should review all code that calls EXECUTE, EXEC, or sp_executesql. È possibile utilizzare query simili alla seguente per identificare procedure contenenti queste istruzioni.You can use queries similar to the following to help you identify procedures that contain these statements. Questa query verifica la presenza di 1, 2, 3 o 4 spazi dopo le parole EXECUTE o EXEC.This query checks for 1, 2, 3, or 4 spaces after the words EXECUTE or EXEC.

SELECT object_Name(id) FROM syscomments  
WHERE UPPER(text) LIKE '%EXECUTE (%'  
OR UPPER(text) LIKE '%EXECUTE  (%'  
OR UPPER(text) LIKE '%EXECUTE   (%'  
OR UPPER(text) LIKE '%EXECUTE    (%'  
OR UPPER(text) LIKE '%EXEC (%'  
OR UPPER(text) LIKE '%EXEC  (%'  
OR UPPER(text) LIKE '%EXEC   (%'  
OR UPPER(text) LIKE '%EXEC    (%'  
OR UPPER(text) LIKE '%SP_EXECUTESQL%';  

Wrapping di parametri con QUOTENAME() e REPLACE()Wrapping Parameters with QUOTENAME() and REPLACE()

In ogni stored procedure selezionata verificare che tutte le variabili usate in Transact-SQL dinamico vengano gestite correttamente.In each selected stored procedure, verify that all variables that are used in dynamic Transact-SQL are handled correctly. Il wrapping dei dati provenienti dai parametri di input della stored procedure o letti da una tabella deve essere eseguito in QUOTENAME() o REPLACE().Data that comes from the input parameters of the stored procedure or that is read from a table should be wrapped in QUOTENAME() or REPLACE(). Ricordare che il valore di @variable passato a QUOTENAME() è di tipo sysname e presenta una lunghezza massima di 128 caratteri.Remember that the value of @variable that is passed to QUOTENAME() is of sysname, and has a maximum length of 128 characters.

@variable Wrapper consigliatoRecommended wrapper
Nome di un'entità a sicurezza direttaName of a securable QUOTENAME(@variable)
Stringa di ≤ 128 caratteriString of ≤128 characters QUOTENAME(@variable, '''')
Stringa di > 128 caratteriString of > 128 characters REPLACE(@variable,'''', '''''')

Quando si utilizza questa tecnica, è possibile rivedere un'istruzione SET nel modo seguente:When you use this technique, a SET statement can be revised as follows:

--Before:  
SET @temp = N'SELECT * FROM authors WHERE au_lname ='''   
 + @au_lname + N'''';  

--After:  
SET @temp = N'SELECT * FROM authors WHERE au_lname = '''   
 + REPLACE(@au_lname,'''','''''') + N'''';  

Attacco intrusivo consentito dal troncamento dei datiInjection Enabled by Data Truncation

Qualsiasi Transact-SQLTransact-SQL dinamico assegnato a una variabile verrà troncato se risulta maggiore del buffer allocato per quella variabile.Any dynamic Transact-SQLTransact-SQL that is assigned to a variable will be truncated if it is larger than the buffer allocated for that variable. Un utente malintenzionato in grado di imporre il troncamento delle istruzioni passando stringhe inaspettatamente lunghe a una stored procedure può modificare il risultato.An attacker who is able to force statement truncation by passing unexpectedly long strings to a stored procedure can manipulate the result. La stored procedure creata dallo script seguente, ad esempio, è vulnerabile agli attacchi intrusivi consentiti dal troncamento.For example, the stored procedure that is created by the following script is vulnerable to injection enabled by truncation.

CREATE PROCEDURE sp_MySetPassword  
@loginname sysname,  
@old sysname,  
@new sysname  
AS  
-- Declare variable.  
-- Note that the buffer here is only 200 characters long.   
DECLARE @command varchar(200)  
-- Construct the dynamic Transact-SQL.  
-- In the following statement, we need a total of 154 characters   
-- to set the password of 'sa'.   
-- 26 for UPDATE statement, 16 for WHERE clause, 4 for 'sa', and 2 for  
-- quotation marks surrounded by QUOTENAME(@loginname):  
-- 200 – 26 – 16 – 4 – 2 = 154.  
-- But because @new is declared as a sysname, this variable can only hold  
-- 128 characters.   
-- We can overcome this by passing some single quotation marks in @new.  
SET @command= 'update Users set password='   
    + QUOTENAME(@new, '''') + ' where username='   
    + QUOTENAME(@loginname, '''') + ' AND password = '   
    + QUOTENAME(@old, '''')  

-- Execute the command.  
EXEC (@command)  
GO  

Passando 154 caratteri in un buffer di 128 caratteri, un utente malintenzionato può impostare una nuova password per sa senza conoscere quella vecchia.By passing 154 characters into a 128 character buffer, an attacker can set a new password for sa without knowing the old password.

EXEC sp_MySetPassword 'sa', 'dummy',   
'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012'''''''''''''''''''''''''''''''''''''''''''''''''''   

Per questo motivo, è consigliabile usare un buffer di grandi dimensioni per una variabile di comando oppure eseguire direttamente Transact-SQLTransact-SQL dinamico all'interno di un'istruzione EXECUTE .For this reason, you should use a large buffer for a command variable or directly execute the dynamic Transact-SQLTransact-SQL inside the EXECUTE statement.

Troncamento se vengono usati QUOTENAME (@variable, '''') e REPLACE()Truncation When QUOTENAME(@variable, '''') and REPLACE() Are Used

Le stringhe restituite da QUOTENAME() e REPLACE() verranno troncate senza avviso se superano lo spazio allocato.Strings that are returned by QUOTENAME() and REPLACE() will be silently truncated if they exceed the space that is allocated. La stored procedure creata nell'esempio seguente illustra le conseguenze.The stored procedure that is created in the following example shows what can happen.

CREATE PROCEDURE sp_MySetPassword  
    @loginname sysname,  
    @old sysname,  
    @new sysname  
AS  

-- Declare variables.  
    DECLARE @login sysname  
    DECLARE @newpassword sysname  
    DECLARE @oldpassword sysname  
    DECLARE @command varchar(2000)  

-- In the following statements, the data stored in temp variables  
-- will be truncated because the buffer size of @login, @oldpassword,  
-- and @newpassword is only 128 characters, but QUOTENAME() can return  
-- up to 258 characters.  
    SET @login = QUOTENAME(@loginname, '''')  
    SET @oldpassword = QUOTENAME(@old, '''')  
    SET @newpassword = QUOTENAME(@new, '''')  

-- Construct the dynamic Transact-SQL.  
-- If @new contains 128 characters, then @newpassword will be '123... n  
-- where n is the 127th character.   
-- Because the string returned by QUOTENAME() will be truncated,   
-- it can be made to look like the following statement:  
-- UPDATE Users SET password ='1234. . .[127] WHERE username=' -- other stuff here  
    SET @command = 'UPDATE Users set password = ' + @newpassword   
     + ' where username =' + @login + ' AND password = ' + @oldpassword;  

-- Execute the command.  
EXEC (@command);  
GO  

Di conseguenza, l'istruzione seguente imposterà le password di tutti gli utenti sul valore passato nel codice precedenteTherefore, the following statement will set the passwords of all users to the value that was passed in the previous code

EXEC sp_MyProc '--', 'dummy', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678'  

È possibile imporre il troncamento delle stringhe superando lo spazio allocato del buffer quando si utilizza REPLACE().You can force string truncation by exceeding the allocated buffer space when you use REPLACE(). La stored procedure creata nell'esempio seguente illustra le conseguenze.The stored procedure that is created in the following example shows what can happen.

CREATE PROCEDURE sp_MySetPassword  
    @loginname sysname,  
    @old sysname,  
    @new sysname  
AS  

-- Declare variables.  
    DECLARE @login sysname  
    DECLARE @newpassword sysname  
    DECLARE @oldpassword sysname  
    DECLARE @command varchar(2000)  

-- In the following statements, data will be truncated because   
-- the buffers allocated for @login, @oldpassword and @newpassword   
-- can hold only 128 characters, but QUOTENAME() can return   
-- up to 258 characters.   
    SET @login = REPLACE(@loginname, '''', '''''')  
    SET @oldpassword = REPLACE(@old, '''', '''''')  
    SET @newpassword = REPLACE(@new, '''', '''''')  

-- Construct the dynamic Transact-SQL.  
-- If @new contains 128 characters, @newpassword will be '123...n   
-- where n is the 127th character.   
-- Because the string returned by QUOTENAME() will be truncated, it  
-- can be made to look like the following statement:  
-- UPDATE Users SET password='1234…[127] WHERE username=' -- other stuff here   
    SET @command= 'update Users set password = ''' + @newpassword + ''' where username='''   
     + @login + ''' AND password = ''' + @oldpassword + '''';  

-- Execute the command.  
EXEC (@command);  
GO  

Come con QUOTENAME(), il troncamento delle stringhe da parte di REPLACE() può essere evitato dichiarando variabili temporanee sufficientemente lunghe per tutti i casi.As with QUOTENAME(), string truncation by REPLACE() can be avoided by declaring temporary variables that are large enough for all cases. Se possibile, è necessario chiamare QUOTENAME() o REPLACE() direttamente all'interno di Transact-SQLTransact-SQLdinamico.When possible, you should call QUOTENAME() or REPLACE() directly inside the dynamic Transact-SQLTransact-SQL. In caso contrario, è possibile calcolare la dimensione richiesta del buffer nel modo seguente.Otherwise, you can calculate the required buffer size as follows. Per @outbuffer = QUOTENAME(@input), la dimensione di @outbuffer deve essere 2*(len(@input)+1).For @outbuffer = QUOTENAME(@input), the size of @outbuffer should be 2*(len(@input)+1). Quando si usa REPLACE() e le virgolette doppie, come nell'esempio precedente, un buffer di 2*len(@input) è sufficiente.When you use REPLACE() and doubling quotation marks, as in the previous example, a buffer of 2*len(@input) is enough.

Il calcolo seguente tratta tutti i casi:The following calculation covers all cases:

WHILE LEN(@find_string) > 0, required buffer size =  
ROUND(LEN(@input)/LEN(@find_string),0) * LEN(@new_string)   
 + (LEN(@input) % LEN(@find_string))  

Troncamento quando viene usato QUOTENAME(@variable, ']')Truncation When QUOTENAME(@variable, ']') Is Used

Può verificarsi il troncamento quando il nome di un'entità a sicurezza diretta di SQL ServerSQL Server viene passato a istruzioni che utilizzano la forma QUOTENAME(@variable, ']').Truncation can occur when the name of a SQL ServerSQL Server securable is passed to statements that use the form QUOTENAME(@variable, ']'). Nell'esempio riportato di seguito viene illustrata questa situazione.The following example shows this.

CREATE PROCEDURE sp_MyProc  
    @schemaname sysname,  
    @tablename sysname,  
AS  

-- Declare a variable as sysname. The variable will be 128 characters.  
-- But @objectname actually must allow for 2*258+1 characters.   
DECLARE @objectname sysname  
SET @objectname = QUOTENAME(@schemaname)+'.'+ QUOTENAME(@tablename)   
-- Do some operations.  
GO  

Quando si concatenano valori di tipo sysname, è consigliabile usare variabili temporanee di lunghezza sufficiente per contenere 128 caratteri per valore.When you are concatenating values of type sysname, you should use temporary variables large enough to hold the maximum 128 characters per value. Se possibile, chiamare QUOTENAME() direttamente all'interno di Transact-SQLTransact-SQLdinamico.If possible, call QUOTENAME() directly inside the dynamic Transact-SQLTransact-SQL. In caso contrario, è possibile calcolare la dimensione richiesta del buffer, come illustrato nella sezione precedente.Otherwise, you can calculate the required buffer size as explained in the previous section.

Vedere ancheSee Also

EXECUTE (Transact-SQL) EXECUTE (Transact-SQL)
REPLACE (Transact-SQL) REPLACE (Transact-SQL)
QUOTENAME (Transact-SQL) QUOTENAME (Transact-SQL)
sp_executesql (Transact-SQL) sp_executesql (Transact-SQL)
Sicurezza di SQL Server Securing SQL Server