ADD SIGNATURE (Transact-SQL)
Agrega una firma digital a un procedimiento almacenado, una función, un ensamblado o un desencadenador. También agrega una contrafirma a un procedimiento almacenado, una función, un ensamblado o un desencadenador.
Sintaxis
ADD [ COUNTER ] SIGNATURE TO module_class::module_name
BY <crypto_list> [ ,...n ]
<crypto_list> ::=
CERTIFICATE cert_name
| CERTIFICATE cert_name [ WITH PASSWORD = 'password' ]
| CERTIFICATE cert_name WITH SIGNATURE = signed_blob
| ASYMMETRIC KEY Asym_Key_Name
| ASYMMETRIC KEY Asym_Key_Name [ WITH PASSWORD = 'password'.]
| ASYMMETRIC KEY Asym_Key_Name WITH SIGNATURE = signed_blob
Argumentos
module_class
Es la clase del módulo al que se agrega la firma. El valor predeterminado para módulos de ámbito de esquema es OBJECT.module_name
Es el nombre de un procedimiento almacenado, una función, un ensamblado o un desencadenador que se firmará o contrafirmará.CERTIFICATE cert_name
Es el nombre de un certificado con el que está firmado o contrafirmado el procedimiento almacenado, la función, el ensamblado o el desencadenador.WITH PASSWORD = 'password'
Es la contraseña necesaria para descifrar la clave privada del certificado o la clave simétrica. Esta cláusula solo se requiere si la clave privada no está protegida por la clave maestra de la base de datos.SIGNATURE = signed_blob
Especifica el objeto binario grande (BLOB) firmado del módulo. Esta cláusula es útil si desea enviar un módulo sin enviar la clave privada. Si utiliza esta cláusula, solo se necesitan el módulo, la firma y la clave pública para agregar el objeto binario grande firmado a una base de datos. signed_blob es el propio objeto binario grande en formato hexadecimal.ASYMMETRIC KEY Asym_Key_Name
Es el nombre de una clave asimétrica con el que está firmado o contrafirmado el procedimiento almacenado, la función, el ensamblado o el desencadenador.
Comentarios
El módulo que se va a firmar o contrafirmar, y el certificado o la clave simétrica utilizada para firmarlo ya deben existir. En el cálculo de la firma se incluyen todos los caracteres del módulo. Esto incluye saltos de línea y retornos de carro iniciales.
Un módulo se puede firmar y contrafirmar por diversos certificados y claves simétricas.
La firma de un módulo se quita cuando se cambia el módulo.
Si un módulo contiene una cláusula EXECUTE AS, el Id. de seguridad (SID) de la entidad de seguridad también se incluye como parte del proceso de firma.
Advertencia |
---|
La firma de módulos solo se debe utilizar para conceder permisos, nunca para denegarlos ni revocarlos. |
Para obtener más información acerca de las firmas, vea la vista de catálogo sys.crypt_properties.
Contrafirmas
Al ejecutar un módulo firmado, las firmas se agregarán temporalmente al token de SQL, pero se pierden si el módulo ejecuta otro módulo o si termina la ejecución. Una contrafirma es una forma especial de firma. Por si sola, una contrafirma no concede ningún permiso; sin embargo, permite a las firmas realizadas por el mismo certificado o clave asimétrica conservarse mientras dure la llamada realizada al objeto contrafirmado.
Por ejemplo, suponga que la usuaria Alice llama al procedimiento ProcSelectT1ForAlice, que llama al procedimiento procSelectT1, que realiza una selección en la tabla T1. Alice dispone del permiso EXECUTE en ProcSelectT1ForAlice y procSelectT1, pero no tiene el permiso SELECT en T1 y no hay ninguna cadena de propiedad implicada en esta cadena completa. Alice no puede tener acceso a la tabla T1, ni directamente ni a través del uso de ProcSelectT1ForAlice y procSelectT1. Puesto que deseamos que Alice utilice siempre ProcSelectT1ForAlice para el acceso, no es aconsejable concederle permiso para ejecutar procSelectT1. ¿Cómo podemos lograr esto?
Si firmamos procSelectT1, procSelectT1 puede tener acceso a T1 y entonces Alice puede invocar a procSelectT1 directamente y no tiene que llamar a ProcSelectT1ForAlice.
Podríamos denegar el permiso EXCEUTE en procSelectT1 a Alice, pero entonces Alice no podría llamar a procSelectT1 a través de ProcSelectT1ForAlice.
Si solo se firma ProcSelectT1ForAlice, no funcionaría, porque la firma se perdería en la llamada a procSelectT1.
Sin embargo, al contrafirmar procSelectT1 con el mismo certificado que se usó para firmar ProcSelectT1ForAlice, SQL Server mantendrá la firma a través de la cadena de llamadas y permitirá el acceso a T1. Si Alice intenta llamar directamente a procSelectT1, no puede tener acceso a T1, porque la contrafirma no concede ningún derecho. El ejemplo C siguiente muestra el código de Transact-SQL para este ejemplo.
Permisos
Requiere el permiso ALTER para el objeto y el permiso CONTROL para el certificado o la clave asimétrica. Si una clave privada asociada está protegida por una contraseña, el usuario también debe tener la contraseña.
Ejemplos
A. Firmar procedimiento almacenado mediante el uso de un certificado
En el siguiente ejemplo se firma el procedimiento almacenado HumanResources.uspUpdateEmployeeLogin con el certificado HumanResourcesDP.
USE AdventureWorks2008R2;
ADD SIGNATURE TO HumanResources.uspUpdateEmployeeLogin
BY CERTIFICATE HumanResourcesDP;
GO
B. Firmar un procedimiento almacenado mediante el uso de un BLOB firmado
En el siguiente ejemplo se crea una base de datos nueva y un certificado que se utilizará en el ejemplo. El ejemplo crea y firma un procedimiento almacenado simple y recupera la firma BLOB de sys.crypt_properties. Posteriormente, el procedimiento se quita y se vuelve a crear. En el ejemplo se firma el procedimiento utilizando la sintaxis WITH SIGNATURE.
CREATE DATABASE TestSignature ;
GO
USE TestSignature ;
GO
-- Create a CERTIFICATE to sign the procedure.
CREATE CERTIFICATE cert_signature_demo
ENCRYPTION BY PASSWORD = 'pGFD4bb925DGvbd2439587y'
WITH SUBJECT = 'ADD SIGNATURE demo';
GO
-- Create a simple procedure.
CREATE PROC [sp_signature_demo]
AS
PRINT 'This is the content of the procedure.' ;
GO
-- Sign the procedure.
ADD SIGNATURE TO [sp_signature_demo]
BY CERTIFICATE [cert_signature_demo]
WITH PASSWORD = 'pGFD4bb925DGvbd2439587y' ;
GO
-- Get the signature binary BLOB for the sp_signature_demo procedure.
SELECT cp.crypt_property
FROM sys.crypt_properties AS cp
JOIN sys.certificates AS cer
ON cp.thumbprint = cer.thumbprint
WHERE cer.name = 'cert_signature_demo' ;
GO
La firma crypt_property que devuelve esta instrucción será diferente cada vez que cree un procedimiento. Tome nota del resultado para su uso posteriormente en este ejemplo. Para este ejemplo, el resultado que se obtiene es: 0x831F5530C86CC8ED606E5BC2720DA835351E46219A6D5DE9CE546297B88AEF3B6A7051891AF3EE7A68EAB37CD8380988B4C3F7469C8EABDD9579A2A5C507A4482905C2F24024FFB2F9BD7A953DD5E98470C4AA90CE83237739BB5FAE7BAC796E7710BDE291B03C43582F6F2D3B381F2102EEF8407731E01A51E24D808D54B373.
-- Drop the procedure so that a new version can be created.
DROP PROC [sp_signature_demo] ;
GO
-- Re-create the procedure by using the exact text including spaces.
CREATE PROC [sp_signature_demo]
AS
PRINT 'This is the content of the procedure.' ;
GO
-- Add the signature. Use the signature BLOB obtained earlier.
ADD SIGNATURE TO [sp_signature_demo]
BY CERTIFICATE [cert_signature_demo]
WITH SIGNATURE = 0x831F5530C86CC8ED606E5BC2720DA835351E46219A6D5DE9CE546297B88AEF3B6A7051891AF3EE7A68EAB37CD8380988B4C3F7469C8EABDD9579A2A5C507A4482905C2F24024FFB2F9BD7A953DD5E98470C4AA90CE83237739BB5FAE7BAC796E7710BDE291B03C43582F6F2D3B381F2102EEF8407731E01A51E24D808D54B373 ;
GO
C. Acceso a un procedimiento utilizando una contrafirma
El siguiente ejemplo muestra el modo en que la contrafirma puede ayudar a controlar el acceso a un objeto.
-- Create tesT1 database
CREATE DATABASE testDB;
GO
USE testDB;
GO
-- Create table T1
CREATE TABLE T1 (c varchar(11));
INSERT INTO T1 VALUES ('This is T1.');
-- Create a TestUser user to own table T1
CREATE USER TestUser WITHOUT LOGIN;
ALTER AUTHORIZATION ON T1 TO TestUser;
-- Create a certificate for signing
CREATE CERTIFICATE csSelectT
ENCRYPTION BY PASSWORD = 'SimplePwd01'
WITH SUBJECT = 'Certificate used to grant SELECT on T1';
CREATE USER ucsSelectT1 FROM CERTIFICATE csSelectT;
GRANT SELECT ON T1 TO ucsSelectT1;
-- Create a principal with low privileges
CREATE LOGIN Alice WITH PASSWORD = 'SimplePwd01';
CREATE USER Alice;
-- Verify Alice cannoT1 access T1;
EXECUTE AS LOGIN = 'Alice';
SELECT * FROM T1;
REVERT;
-- Create a procedure that directly accesses T1
CREATE PROCEDURE procSelectT1 AS
BEGIN
PRINT 'Now selecting from T1...';
SELECT * FROM T1;
END;
GO
GRANT EXECUTE ON procSelectT1 to public;
-- Create special procedure for accessing T1
CREATE PROCEDURE procSelectT1ForAlice AS
BEGIN
IF USER_ID() <> USER_ID('Alice')
BEGIN
PRINT 'Only Alice can use this.';
RETURN
END
EXEC procSelectT1;
END;
GO;
GRANT EXECUTE ON procSelectT1ForAlice TO PUBLIC;
-- Verify procedure works for a sysadmin user
EXEC procSelectT1ForAlice;
-- Alice still can't use the procedure yet
EXECUTE AS LOGIN = 'Alice';
EXEC procSelectT1ForAlice;
REVERT;
-- Sign procedure to grant it SELECT permission
ADD SIGNATURE TO procSelectT1ForAlice BY CERTIFICATE csSelectT
WITH PASSWORD = 'SimplePwd01';
-- Counter sign proc_select_t, to make this work
ADD COUNTER SIGNATURE TO procSelectT1 BY CERTIFICATE csSelectT
WITH PASSWORD = 'SimplePwd01';
-- Now the proc works.
-- Note that calling procSelectT1 directly still doesn't work
EXECUTE AS LOGIN = 'Alice';
EXEC procSelectT1ForAlice;
EXEC procSelectT1;
REVERT;
-- Cleanup
USE master;
GO
DROP DATABASE testDB;
DROP LOGIN Alice;