SQL Server, ideas y experiencias

Como cambiar la instancia del SQL Server usada por el “Development Storage” del SDK de AZURE

por Jose Mariano Alvarez 23. agosto 2009

El almacenamiento en el entorno de desarrollo

El entorno de desarrollo SDK de Windows Azure incluye el “Development Storage”, que es una herramienta que simula los servicios Blob, Queue y Table disponibles en la nube. Además ofrece una interfaz de usuario para ver el estado y para iniciar o detener estos servicios de almacenamiento local.

El servicio “Development Storage” se basa en una instancia de SQL Server para simular los servidores de almacenamiento de la nube. De forma predeterminada, el almacenamiento de desarrollo está configurado para utilizar una versión “Express“ del SQL Server 2005 o 2008 como base de datos.

Cambiando la instancia

Cuando ya tenemos un entorno de desarrollo con el SQL Server instalado y este no es la edición “Express” generalmente ocurre que la instancia es una instancia DEFAULT o es una instancia con nombre pero no se llama “express”. Por ejemplo es muy común tener la edición SQL Server 2008 Developer edition en el entorno de desarrollo. Si queremos utilizar esta instancia SQL Server previamente instalada y que no se llama “express” tenemos que reconfigurar nuestro entorno de desarrollo.

Para poder configurar el “development storage”, se debe tener privilegios de administrador del equipo. El programa de línea de comandos DSInit.exe inicializa el “development storage” en el entorno de desarrollo local. Esta herramienta se ejecuta automáticamente la primera vez que se inicia el “development storage” mediante la ejecución del programa DevelopmentStorage.exe y no es necesario ejecutarla a menos que queramos reinicializarlo o cambiarlo como es en nuestro caso. La herramienta DSInit.exe se instala en el directorio C: \ Archivos de programa \ Windows Azure SDK \ v1.0 \ bin \.

Para que el servicio “development storage” utilice otra instancia local del SQL Server tenemos que ejecutar el DSInit con el parámetro /SQLInstance, pasándole el nombre de la instancia del SQL Server de destino. Se puede llamar a DsInit.exe /SQLInstance en cualquier momento para configurar el “development storage” para que apunte a una instancia diferente de SQL Server.

Hay que utilizar el nombre de la instancia de SQL Server sin el calificativo de servidor o “.” para indicar la instancia “Default”

Si disponemos de una instancia local con nombre, por ejemplo la instancia es SQLTotalJMA\SQL2008 como es en mi caso, debemos ejecutar “DSInit.exe /sqlinstance:SQL2008” como muestra la imagen.

DEvelopment Storage DsInit

Esto nos configura el entorno de desarrollo como muestra la siguiente imagen

DsInitResultados

Tags:

Artículos

Cómo ejecutar xp_cmdshell con mínimos permisos

por Jose Mariano Alvarez 3. agosto 2009

El procedimiento almacenado xp_cmdshell es esencialmente un mecanismo para ejecutar llamadas en el sistema operativo utilizando el contexto de SQL Server (es decir, la cuenta de Windows utilizada para iniciar el servicio del SQL Server) o una cuenta proxy que puede ser configurada para ejecutar xp_cmdshell con diferentes credenciales. Si bien habilitar y utilizar este procedimiento almacenado no es una buena práctica, ciertas aplicaciones usan esta técnica y a veces puede ser necesario acceder a la línea de comandos del sistema operativo para ejecutar algún programa fuera del SQL Server. En estos casos tenemos que tener mucho cuidado en como habilitamos y damos permisos para que el usuario pueda acceder a los recursos del sistema operativo con mínimos permisos. En este artículo analizaremos algunos detalles y de cómo habilitarlo con menos permisos que los indicado en la ayuda.

El procedimiento almacenado xp_cmdshell

Para ejecutar un programa fuera del contexto del SQL Server se utiliza el procedimiento almacenado extendido xp_cmdshell, Con este procedimiento almacenado extendido podemos ejecutar cualquier proceso de línea de comandos, por lo que no solo se pueden ejecutar programas EXE sino que se puede ejecutar un archivo de lotes (BAT o CMD).

Debemos tener sumo cuidado en cómo se utiliza este procedimiento almacenado ya que si el contexto de ejecución tiene permisos de administrador local del equipo por ejemplo el programa o un código inyectado pueden agregar un usuario administrador del equipo (del WIndows) utilizando NET USER y NET GROUP.

En SQL Server 2000, por los riesgos de seguridad que implica y para limitar el acceso al xp_cmdshell , su uso está restringido por defecto o en forma predeterminada solo a los miembros de la función de servidor o rol sysadmin. Para extender los derechos a otros usuarios se puede utilizar el comando GRANT.

En SQL Server 2005 el uso de xp_cmdshell está desactivado por defecto como mecanismo de protección para minimizar los riesgos de seguridad de código no deseado en ejecución dentro o fuera de SQL Server de SQL Server. Por ello, si no se habilita la ejecución del xp_cmdshell ni siquiera los administradores del SQL Server (grupo de servidor sysadmin) podrán ejecutarlo.

Por ejemplo si ejecutamos como administradores:

exec xp_cmdshell 'dir c:\*.*'

El resultado es:

Msg 15281, Level 16, State 1, Procedure xp_cmdshell, Line 1

SQL Server blocked access to procedure 'sys.xp_cmdshell' of component 'xp_cmdshell' because this component is turned off as part of the security configuration for this server. A system administrator can enable the use of 'xp_cmdshell' by using sp_configure. For more information about enabling 'xp_cmdshell', see "Surface Area Configuration" in SQL Server Books Online.

 

Para poder ejecutar el procedimiento almacenado extendido xp_cmdshell debemos habilitarlo haciendo:

--Habilito la ejecucion del xp_cmdshell

EXEC sp_configure 'show advanced options', 1
GO

RECONFIGURE
GO

EXEC sp_configure 'xp_cmdshell', 1
GO

RECONFIGURE
GO

Ahora vemos que si volvemos a ejecutar el scrip T-SQL anterior como administrador del SQL Server vemos que nos responde cuando estamos autenticados como administradores. El proceso de Windows creado por xp_cmdshell dispone de los mismos derechos de seguridad que la cuenta de servicio de SQL Server la cual tenía los permisos adecuados en la raíz del disco.

 

Cuenta proxy para el xp_cmdshell

Cuando es llamada por un usuario que no pertenece al rol (función de servidor) sysadmin, el xp_cmdshell se conecta a Windows con el nombre de la cuenta y la contraseña almacenados en la credencial con el nombre ##xp_cmdshell_proxy_account## en lugar de usar la cuenta de servicio por lo que habrá que indicarla previamente o sino dará error.

Vamos a probar ahora con un login que solo tiene permisos mínimos

--Creamos el login 
CREATE LOGIN [Prueba]
WITH PASSWORD=N'<la contraseña del usuario>',
DEFAULT_DATABASE=[master],
CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO

Para crear la credencial de la cuenta de proxy hay que ejecutar sp_xp_cmdshell_proxy_account y como parámetros el nombre del usuario y la contraseña de Windows.

-- Asigno la proxy account
EXEC sp_xp_cmdshell_proxy_account
N'sqltotal\mariano',
N'<la contraseña del usuario>'

El resultado es:

Msg 15137, Level 16, State 1, Procedure sp_xp_cmdshell_proxy_account, Line 1

An error occurred during the execution of sp_xp_cmdshell_proxy_account. Possible reasons: the provided account was invalid or the '##xp_cmdshell_proxy_account##' credential could not be created. Error code: '5'.

Aquí nos encontramos con un nuevo problema si estamos usando Windows Vista como es mi caso. No podemos asignar esta contraseña por más que el usuario usado sea administrador del SQL Server debido al UAC. Por lo tanto debemos ejecutar este comando en una nueva instancia del SQL Server Management Studio como administrador usando la opción “RUN AS ADMINISTRATOR” (ejecutar como administrador).

Luego de asignar la cuanta proxy como administrador local y del SQL Server abrimos una nueva ventana con el usuario prueba y verificamos que pasa:

exec xp_cmdshell 'dir c:\*.*'

Y el resultado es:

Msg 229, Level 14, State 5, Procedure xp_cmdshell, Line 1

The EXECUTE permission was denied on the object 'xp_cmdshell', database 'mssqlsystemresource', schema 'sys'.

En este punto si revisamos la ayuda en el link siguiente podemos verificar que nos dice que se requiere el permiso CONTROL SERVER, para poder ejecutar xp_cmdshell el cual no es adecuado ya que posibilita tomar el control total del SQL Server.

xp_cmdshell en la ayuda del SQL Server

Por lo tanto vamos a crear el usuario dentro de la base de datos master relacionado con el login y asignar solo el permiso de ejecución del procedimiento almacenado:

-- Creo el usuario en la base de datos
-- master para el login anterior
USE [master]
GO

CREATE USER [Prueba] FOR LOGIN [Prueba]
GO

-- Asigno el permiso de ejecucion al usuario
use [master]
GO

GRANT EXECUTE ON [sys].[xp_cmdshell]
TO [Prueba]
GO

Si ahora probamos veremos que es posible ejecutar el procedimiento almacenado xp_cmdshell sin ser administrador sin asignar permisos de CONTROL SERVER.

Veamos qué pasa si tenemos asignado solo el permiso de ejecución del procedimiento almacenado pero no existe la credencial.

Como administradores eliminamos la cuenta proxy:

EXEC sp_xp_cmdshell_proxy_account null

Probamos la ejecucion del procediemiento almacenado nuevamente con el usuario prueba

exec xp_cmdshell 'dir c:\*.*'

El resultado es:

Msg 15153, Level 16, State 1, Procedure xp_cmdshell, Line 1

The xp_cmdshell proxy account information cannot be retrieved or is invalid. Verify that the '##xp_cmdshell_proxy_account##' credential exists and contains valid information. 

Conclusiones

  • No es recomendable utilizar el procedimiento almacenado xp_cmdshell.
  • Para poder ejecutarlo se requiere habilitar su ejecución en la configuración del SQL Server utilizando el procedimiento almacenado sp_configure.
  • Si somos administradores podemos ejecutar el procedimiento xp_cmdshell el cual utiliza la cuenta de servicio del SQL Server
  • Si no somos administradores utiliza la cuenta proxy que debe estar definida.
  • Si no somos administradores solo debemos tener permiso de ejecución en el procedimiento almacenado xp_cmdshell y no hace falta asignar el permiso CONTROL SERVER como dice la ayuda.

Tags: , ,

Artículos

Cómo permitir el uso del Profiler o la creación de Trazas sin tener derechos de administrador

por Jose Mariano Alvarez 31. julio 2009

La ejecución del SQL Server Profiler requiere al menos del permiso de servidor ALTER TRACE. Este es el mismo permiso que se requiere para poder ejecutar los procedimientos almacenados de T-SQL que se utilizan para crear las trazas.

Veamos un ejemplo.

Creamos un usuario con mínimos permisos :

USE [master]

GO

-- creamos el Login 

CREATE LOGIN [prueba] 

WITH PASSWORD=N'pruebaPass', 

DEFAULT_DATABASE=[master], 

CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF

GO

Luego podemos verificar que no se puede acceder mediante el profiler:

ProfilerPrbPerm

Hacer click en la imagen para agrandarla.

Asignamos el permiso de servidor ALTER TRACE con lo cual le concedemos el permiso de hacer trazas y conectar el Profiler para realizar un seguimiento.

GRANT ALTER TRACE 

TO [Prueba]

GO

Luego nos conectamos desde el Profiler y verificamos que ahora si se puede conectar.

Entonces ejecutamos :

CREATE LOGIN [prueba2] 

WITH PASSWORD=N'pruebaPass', 

DEFAULT_DATABASE=[master], 

CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF

GO

exec sp_help 'sys.indexes'

Como puede verse en la próxima imagen siguiente, el Profiler funciona y como seleccionamos el evento SQL:BatchStarting nos muestra las sentencias que ejecutamos.

CreateLoginEnProfiler

Hacer click en la imagen para agrandarla.

Consideraciones de seguridad importantes al asignar el permiso ALTER TRACE

Es importante ver que en el caso del CREATE LOGIN nos oculta los datos del usuario y la contraseña. Sin embargo nos muestra el parámetro del procedimiento almacenado sp_help.

Como los usuarios que tienen el permiso ALTER TRACE pueden ver las consultas capturadas, se debe tener cuidado ya que las mismas pueden contener datos confidenciales, como contraseñas que se pasan como parámetros en los procedimientos almacenados. El caso mas común es cuando se utilizan mecanismos propietarios de autenticación. Por lo tanto, es importante conceder estos permisos solo a los usuarios que tengan autorización para ver información confidencial.

Tags: , , , ,

Artículos

Como numerar eficientemente las filas de una consulta select

por Jose Mariano Alvarez 10. julio 2009

Uno de las preguntas más frecuentes es cómo numerar la filas de una consulta. En SQL Server 2005 se introdujo ROW_NUMBER() para poder realizar esta operación fácilmente. Sin embargo en los casos en que no la podemos usar como en SQL Server 2000 existen creencias de que los subquery pueden ser alternativas eficientes y las consecuencias suelen ser catastróficas luego de que el volumen de registros crece.

Usando la tabla AdventureWorks2008.Sales.Customer vamos a probar cuatro estrategias y sus consecuencias.

 

Usando un subquery como habitualmente se sugiere en SQL Server 2000

Select  
    (
        select
            COUNT(*) + 1
        from AdventureWorks2008.Sales.Customer B 
        where b.AccountNumber  < a.AccountNumber
    ) as fila, 
    a.*
from AdventureWorks2008.Sales.Customer a
order by rowguid 

El resultado del plan muestra como se anida un SCAN de la tabla dentro de un NESTED LOOP lo cual genera un severo problema de rendimiento.

  |--Compute Scalar(DEFINE:([Expr1006]=[Expr1004]+(1)))
       |--Nested Loops(Inner Join, OUTER REFERENCES:([a].[CustomerID]))
            |--Compute Scalar(DEFINE:([a].[AccountNumber]=[AdventureWorks2008].[Sales].[Customer].[AccountNumber] as [a].[AccountNumber]))
            |    |--Compute Scalar(DEFINE:([a].[AccountNumber]=isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID]),'')))
            |         |--Sort(ORDER BY:([a].[rowguid] ASC))
            |              |--Clustered Index Scan(OBJECT:([AdventureWorks2008].[Sales].[Customer].[PK_Customer_CustomerID] AS [a]))
            |--Compute Scalar(DEFINE:([Expr1004]=CONVERT_IMPLICIT(int,[Expr1010],0)))
                 |--Stream Aggregate(DEFINE:([Expr1010]=Count(*)))
                      |--Index Spool(SEEK:([B].[AccountNumber] < isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID]),'')))
                           |--Compute Scalar(DEFINE:([B].[AccountNumber]=isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [B].[CustomerID]),'')))
                                |--Index Scan(OBJECT:([AdventureWorks2008].[Sales].[Customer].[IX_Customer_TerritoryID] AS [B]))

 

Si vemos a continuación los detalles de la cantidad de IO podemos ver claramente como la cantidad de lecturas lógicas es de 1103320,

Table 'Worktable'.
    Scan count 19820,
    logical reads 1103320,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.


Table 'Customer'.
    Scan count 2,
    logical reads 160,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.

El resultado de la consulta tardo 1 minuto y 37 segundos

 

 

Usando la nueva sintaxis ROW_NUMBER() introducida en SQL Server 2005

Select
       ROW_NUMBER() OVER (ORDER BY a.AccountNumber ) as fila,
       A.* 
from 
       AdventureWorks2008.Sales.Customer a
order by 
       rowguid 

El resultado del plan muestra no se anida en este caso ningún SCAN sino que es un plan secuancial y muy eficiente.

  |--Sort(ORDER BY:([a].[rowguid] ASC))
       |--Sequence Project(DEFINE:([Expr1002]=row_number))
            |--Segment
                 |--Compute Scalar(DEFINE:([a].[AccountNumber]=[AdventureWorks2008].[Sales].[Customer].[AccountNumber] as [a].[AccountNumber]))
                      |--Sort(ORDER BY:([a].[AccountNumber] ASC))
                           |--Compute Scalar(DEFINE:([a].[AccountNumber]=isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID]),'')))
                                |--Clustered Index Scan(OBJECT:([AdventureWorks2008].[Sales].[Customer].[PK_Customer_CustomerID] AS [a]))

 

Vemos como el resultado de aplicar la nueva función ha cambiado y solo se realizan 123 lecturas lógicas.

Table 'Customer'.
    Scan count 1,
    logical reads 123,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.

 El resultado de la consulta tardo 1 segundo.

 

 

Usando la función IDENTITY() como en SQL Server 2000

En este caso se debe recurrir a una tabla temporal pero vemos que el beneficio es sustancial.

Debido a lo que ocurre con la función IDENTITY() y el ORDER BY se debe crear una tabla temporal para insertar los registros. Les dejo el Enlace a “The behavior of the IDENTITY function when used with SELECT INTO or INSERT .. SELECT queries that contain an ORDER BY clause”.

http://support.microsoft.com/kb/273586

NOTA: Quiero agradecer a Alejandro Mesa quien me hizo el comentario del error en los foros respecto de este comportamiento que yo había omitido en el Post el cual ya se encuentra actualizado y corregido según la documentacióní.

Creamos la tabla temporal para ordenar los registros

CREATE TABLE [dbo].[#Clientes](
    [fila] [int] IDENTITY(1,1) NOT NULL,
    [CustomerID] [int] NULL,
    [PersonID] [int] NULL,
    [StoreID] [int] NULL,
    [TerritoryID] [int] NULL,
    [AccountNumber] [varchar](10) NOT NULL,
    [rowguid] [uniqueidentifier] NOT NULL,
    [ModifiedDate] [datetime] NOT NULL
) ON [PRIMARY]
GO

 

Esta es la parte de la consulta donde se generan los números de fila.

Insert into #Clientes
(
    CustomerID, 
    PersonID, 
    StoreID, 
    TerritoryID, 
    AccountNumber, 
    rowguid, 
    ModifiedDate
)
Select     
    cast(CustomerID as int) as CustomerID , 
    PersonID, 
    StoreID, 
    TerritoryID, 
    AccountNumber, 
    rowguid, 
    ModifiedDate
from AdventureWorks2008.Sales.Customer a
ORDER BY a.AccountNumber 

Ahora vemos nuevamente que no se anida un SCAN en el plan por lo que resulta mucho más eficiente que en el caso del subquery.

  |--Table Insert(OBJECT:([#Clientes]), SET:([#Clientes].[CustomerID] = [Expr1006],[#Clientes].[PersonID] = [AdventureWorks2008].[Sales].[Customer].[PersonID] as [a].[PersonID],[#Clientes].[StoreID] = [AdventureWorks2008].[Sales].[Customer].[StoreID] as [a
       |--Compute Scalar(DEFINE:([Expr1007]=getidentity((-7),(0),N'#Clientes')))
            |--Top(ROWCOUNT est 0)
                 |--Compute Scalar(DEFINE:([a].[AccountNumber]=[AdventureWorks2008].[Sales].[Customer].[AccountNumber] as [a].[AccountNumber], [Expr1006]=CONVERT(int,[AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID],0)))
                      |--Sort(ORDER BY:([a].[AccountNumber] ASC))
                           |--Compute Scalar(DEFINE:([a].[AccountNumber]=isnull('AW'+[AdventureWorks2008].[dbo].[ufnLeadingZeros]([AdventureWorks2008].[Sales].[Customer].[CustomerID] as [a].[CustomerID]),'')))
                                |--Clustered Index Scan(OBJECT:([AdventureWorks2008].[Sales].[Customer].[PK_Customer_CustomerID] AS [a]))

 

Si vemos los resultados en I/O solo se realizan 123 lecturas logicas

Table 'Customer'.
    Scan count 1,
    logical reads 123,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.

Select * 
from #Clientes c
order by C.rowguid 

El plan de esta parte es el SCAN y el SORT.

|--Sort(ORDER BY:([c].[rowguid] ASC))
       |--Table Scan(OBJECT:([tempdb].[dbo].[#Clientes] AS [c]))

 

Si vemos los resultados en I/O solo se realizan 167 lecturas logicas

Table '#Clientes_000000000007'.
    Scan count 1,
    logical reads 167,
    physical reads 0,
    read-ahead reads 0,
    lob logical reads 0,
    lob physical reads 0,
    lob read-ahead reads 0.

Queda eliminar la tabla temporal con

drop table #Clientes 

El total acumulado de tiempo fue de 1 segundo.

 

 

Conclusión:

 

Caso Lecturas Tiempo
Subquery 1103480 97 seg
Row_Number() 123 1 seg
Tabla temporal + Identity() 280 1 seg

Vemos que es mucho más eficiente la tercera opción usando una tabla temporal y la función identiy() que la opción de la subquery (subconsulta). Sin embargo esta no es  tan eficiente como en el caso de la nueva sintaxis de SQL Server 2005/8 con ROW_NUMBER(). Por lo tanto si tiene SQL Server 2005 o SQL Server 2008 Lo mejor es usar la funcion ROW_NUMBER() y si tienen SQL Server 2000 la mejor opción es usar la tabla temporal y la función Identity().

 

En todos los casos todas las lecturas fueron lógicas ya que la tabla tenia todas las paginas en memoria.

NOTA: Me falta comparar la alternativa de usar CLR y de usar un cursor de T-Sql.

Tags: , , ,

Artículos

Soporte al lenguaje T-SQL en SQL Azure Database

por Jose Mariano Alvarez 9. julio 2009

Este es en parte una traducción y también un resumen de la información de alto nivel de las características de T-SQL soportadas en SQL AZURE DATABASE según fue publicada en el blog “SQL Data Services Team Blog” mientras se escribe la documentación más detallada. SQLAzure

En su primera versión, SQL Azure Database dará soporte a un subconjunto de T-SQL. Cada construcción de T-SQL puede clasificarse como soportada, en parte soportada o no soportada. Soportado significa que no hay diferencia en la forma en que SQL AZURE DATABASE trata a una declaración, sentencia o una función en comparación con el SQL Server. Parcialmente soportado se entiende como que SQL AZURE DATABASE soporta un subconjunto de la funcionalidad. No soportado significa que esa característica no está soportada por SQL AZURE DATABASE. Al momento de escribir el artículo no está previsto añadir nuevas construcciones al lenguaje T-SQL o cambiar la forma en que la funcionalidad actual trabaja.

En muchos aspectos, SQL AZURE DATABASE es muy similar a una instancia de SQL Server. Sin embargo, existen algunas diferencias:

  • SQL AZURE DATABASE es un sistema multi-alquilado
  • Los recursos de hardware son de propiedad, organizados y mantenidos por Microsoft
  • SQL AZURE DATABASE es un servicio

Estas diferencias imponen ciertos requisitos en el sistema, que, a su vez, se traducen en restricciones en el T-SQL disponible para quien contrata el servicio. Estas restricciones se encajan en tres rubros:

  • Manipulación de recursos. Se van a bloquear las declaraciones y las opciones que tratan de manipular directamente los recursos físicos. Esta categoría incluye RESOURCE GOVERNOR, referencias de archivos y filegroups y algunas declaraciones DDL físicas.
  • Cosas que, o no son aplicables en el mundo de los servicios o son atendidos por Microsoft. Replicación es un buen ejemplo de esto.
  • Por último, habrá algunas cosas que simplemente no será posibles permitirlas en la primera versión o release. Cada característica que se añade a SQL AZURE DATABASE requiere trabajo adicional para garantizar que el servicio sigue siendo eficiente, escalable y seguro. Este trabajo lleva tiempo extra, lo que significa que algunas de las características tendrán que esperar hasta la versión 2. Por ejemplo soporte a consultas distribuidas y CLR son algunos ejemplos de las funciones de esta categoría.

Qué queda adentro y que no

Los siguientes detalles muestran que está previsto soportar en la versión 1 separado en tres categorías, DDL, DML y manejabilidad.

DDL

SDS soportara total o parcialmente la creacion manipulación y eliminación de los siguiente tipos de objetos.

  • FUNCTION
  • INDEX
  • PROCEDURE
  • ROLE
  • SCHEMA
  • STATISTICS
  • SYNONIM
  • TABLE
  • TRIGGER
  • VIEW

La mayoría de las sentencias CREATE y ALTER de los objetos anteriores serán soportadas parcialmente debido a las restricciones impuestas. Por ejemplo la opción filegroup de la sentencia CREATE TABLE no será soportada.

Los usuarios no podrán crear objetos si no son de los tipos indicados en la lista precedente

DML

La mayoría de las sentencias DML serán soportadas total o parcialmente, incluyendo:

  • SELECT/INSERT/UPDATE/DELETE functionality
  • DML triggers
  • JOINs
  • Transactions
  • La mayoría de las funciones incorporadas (agregaciones, matemáticas, fecha, hora, ranking, etc.)

Manejabilidad

Este es el área en la cual existirán más restricciones. Esto son algunos de los puntos principales:

Lo que funcionará

  • Tuning via SET SHOWPLAN y SET STATISTICS
  • Index tuning mediante create y drop index
  • Actualización de estadísticas mediante UPDATE STATISTICS
  • Información de vistas de esquema y cátalo del sistema (schema views and system catalog views)
  • Alta disponibilidad es parte del servicio
  • La próxima versión de SQL Server Management Studio y Visual Studio funcionarán con SQL Azure Database

Lo que no funcionará

  • Backup (se recomienda BCP o SSIS como alternativa de copia).
  • Server options (sp_configure)
  • SQL Profiler
  • SQL traceflag

 

Otros detalles

Pueden ver los detalles en el artículo original en

TSQL Support in SQL Azure Database

Tags: ,

Artículos

Cómo validar un usuario con funciones de cifrado del SQL Server sin almacenar la contraseña en una tabla

por Jose Mariano Alvarez 6. julio 2009

Aunque usar mecanismos de autenticación propios no es lo más recomendable, podemos utilizar,  con cierta seguridad, las funciones de cifrado EncryptByPassPhrase y DecryptByPassPhrase incorporadas al T-SQL del SQL Server 2005 y SQL Server 2008 para implementar un mecanismo propio, que además no almacena ni siquiera la contraseña cifrada como mecanismo adicional de seguridad.

Para evitar que se pueda obtener la contraseña, vamos a utilizar un mecanismo que evita almacenarla y en su lugar vamos a utilizar un mecanismo de cifrado mediante clave simétrica que almacena, en su reemplazo, el usuario utilizando la contraseña ingresada por el usuario como frase de contraseña o clave de cifrado.  Esto prácticamente restringe los posible ataques a la prueba por fuerza bruta de la contraseña.

Se conoce a la frase de contraseña como una contraseña que incluye espacios. Dado los requerimientos de seguridad crecientes, que implican tener claves cada vez más complejas y grandes, la ventaja de usar una frase de contraseña es que es más fácil recordar una frase larga con significado que una cadena de caracteres larga. Las función EncryptByPassPhrase que vamos a usar para cifrar no comprueba la existencia de espacios en la frase de contraseña ni la complejidad de la contraseña, por lo que queda como responsabilidad del programador realizar esta comprobación.

Los parámetros de EncryptByPassPhrase son:

  • passphrase: Frase de contraseña a partir de la cual se genera una clave simétrica.
  • cleartext: Texto no cifrado que se va a cifrar.
  • add_authenticator: Indica si se cifrará un autenticador junto con el texto sin cifrar. 1 si se va a agregar un autenticador. int.
  • authenticator: Datos a partir de los cuales se obtiene un autenticador. sysname.

El resultado de la función es el dato cifrado el cual se obtiene como varbinary con un tamaño máximo de 8.000 bytes.

Este código crea una base de datos de ejemplo y una tabla que almacena los datos

use master
go

-- Creo una base de datos para la prueba
Create database Prueba
go
use Prueba
go

-- Creo una tabla de usuarios que no almacena 
-- la contraseña ni la contraseña cifrada
-- sino el usuario cifrado con la contraseña como 
-- clave de cifrado.
Create table dbo.Usuarios
(
    Usuario varchar(100) primary key,
    HashUsuario varbinary(8000)
)
go

Para agregar los datos del usuario usaremos el siguiente procedimiento almacenado que permite agregar al usuario con el correspondiente usuario cifrado para usar luego al validar las credenciales.

-- procedimiento para cifrar y guardar el usuario
Create procedure dbo.AgregarUsuario
    @Usuario varchar(100),
    @Contrasena varchar(100)
as 
Insert into Usuarios(Usuario,HashUsuario) 
values(
    @Usuario,
    EncryptByPassPhrase(@Contrasena ,@Usuario ,0)
)
GO

Se debe tener en cuenta que cada vez que se ejecuta la función EncryptByPassPhrase, aunque usemos los mismos parámetros, el resultado cifrado es diferente, por lo cual no se pueden comparar los resultados cifrados de dos ejecuciones y por lo tanto se debe utilizar la función de descifrado para validar.

La función de descifrado es DecryptByPassPhrase y los parámetros son:

  • passphrase: Frase de contraseña que se utilizará para generar la clave para el descifrado.
  • 'ciphertext':Es el texto cifrado que hay que descifrar. Es del tipo varbinary. El tamaño máximo es 8.000 bytes.
  • add_authenticator: Indica si se ha cifrado un autenticador junto con el texto simple. Es 1 si se ha utilizado un autenticador. int.
  • authenticator: Son los datos del autenticador. sysname.

El  Tipos de valor devueltos es varbinary con un tamaño máximo de 8.000 bytes. La función DecryptByPassPhrase  devuelve NULL si se utiliza la información de autenticador errónea o la frase de contraseña errónea.

Veamos el ejemplo para validar el usuario

-- Procediemiento para descifrar y validar
Create procedure dbo.ValidarUsuario
    @Usuario varchar(100),
    @Contrasena varchar(100)
as 
if (
    Select COUNT(*)
    from    Usuarios 
    where    Usuario = @Usuario
    and        cast(DECRYPTBYPASSPHRASE(@Contrasena,HashUsuario,0) as varchar(100)) = @Usuario
) > 0
    print 'Validado'
else
    print 'Error en credenciales'
go

Ya tenemos todo el código necesario vamos a probarlo con las siguientes sentencias:

Agregamos un usuario

-- Agrego un usuario de prueba
exec dbo.AgregarUsuario 'Mariano', 'PassW0rd';
go

Probamos con una contraseña válida y vemos que nos imprime el cartel de validado. Luego probamos con una contraseña errónea y vemos que nos imprime el cartel de credenciales erróneas.

-- Probamos con la clave correcta
exec dbo.ValidarUsuario 'Mariano', 'PassW0rd';
GO

-- Probamos con la clave incorrecta
exec dbo.ValidarUsuario 'Mariano', 'otra password';
go

Para eliminar todo usamos el siguiente código

-- Borramos todo
use master;
drop database Prueba;
go

Conclusión

Vemos que se puede validar las credenciales, mediante el usuario y la contraseña de una manera eficiente con la funciones de cifrado y descifrado del SQL Server sin almacenar siquiera la contraseña cifrada lo que aumente la seguridad notablemente en los casos que queremos usar un mecanismo propietario.

Tags: ,

Artículos

Creando un instalador del SQL Server 2008 con el SP1 incorporado

por Jose Mariano Alvarez 29. junio 2009

Como les comente en el artículo SQL Server 2008 Service Pack 1 y actualizaciones de abril 2009es posible crear un instalador que incorpore el service pack para instalar en un solo paso el SQL Sever 2008 actualizado. En esa ocasión les había dejado un link con el detalles de como hacerlo.

Hace unos días, se ha actualizado el documento que explica como hacer el instalador del SQL Server 2008 con el Service pack 1 incorporado. Como varios me han preguntado les dejo el enlace nuevamente con los detalles (en inglés) en el siguiente link:

SQL Server Setup : Creating a merged (slipstreamed) drop containing SQL Server 2008 RTM + Service Pack 1

Tags: , , ,

Artículos

Powered by SQL Total Consulting


View Jose Mariano Alvarez's profile on LinkedIn

 Add to Technorati Favorites 

Calendar

<<  agosto 2017  >>
lumamijuvido
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar

Locations of visitors to this page

Widget Twitter not found.

Root element is missing.X


Valid XHTML 1.0 Transitional

Valid CSS!