lunes, 8 de julio de 2013

SQL SERVER 2008 R2: Limitar conexiones de inicios de sesión con Triggers DDL.

Hay veces que es interesante impedir que un Inicio de Sesión  establezca más de una conexión con el servidor. Para ello SQL Server 2008 R2 incorporar los llamados Desencadenadores (triggers) DDL. Este artículo nos servirá para poner un ejemplo de estos interesantes triggers, que a diferencia de los que usamos normalmente, que se disparan al realizar modificaciones, inserciones o borrados de datos de una tabla, estos se disparan ante alteraciones en la estructura de la base de datos, por ejemplo, o cualquier otro evento sobre el servidor.

Según la MSDN de microsoft, un Desencadendor DDL es: "Los desencadenadores DDL se inician en respuesta a una variedad de eventos de lenguaje de definición de datos (DDL). Estos eventos corresponden principalmente a las instrucciones de Transact-SQL que comienzan por las palabras clave CREATE, ALTER, DROP, GRANT, DENY, REVOKE o UPDATE STATISTICS. Algunos procedimientos almacenados del sistema que ejecutan operaciones de tipo DDL también pueden activar desencadenadores DDL". Podéis encontrar mas información aquí.

Centrandonos en el ejemplo:  Vamos a limitar que un inicio de sesión no pueda realizar mas de tres conexiones simultaneas al Servidor de SQL Server 2008 R2. Para ello vamos a programar un trigger DDL sobre el Inicio de Sesión deseado y el evento de LOGON.

Lo primero que hacemos es crear un nuevo Inicio de Sesión con el Management Studio, para ello hacemos click derecho sobre la carpeta "Seguridad", luego en Nuevo/Inicio de Sesión. Lo configuramos como en la imagen.


Ahora vamos a darle todos los permisos posibles, es decir, será administrador.



Creamos por último el trigger DDL para controlar el número de conexiones:


01 USE master;
02 GO
03 CREATE TRIGGER limite3conexiones_usuarioLimitado
04 ON ALL SERVER WITH EXECUTE AS 'usuarioLimitado'
05 FOR LOGON
06 AS
07 BEGIN
08 IF ORIGINAL_LOGIN()= 'usuarioLimitado' AND
09 (SELECT COUNT(*) FROM sys.dm_exec_sessions
10 WHERE is_user_process = 1 AND
11 original_login_name = 'usuarioLimitado') > 3
12 ROLLBACK;
13 END;

Para probarlo, tan solo tenemos que realizar varias conexiones con el inicio de sesión que hemos creado, hasta superar el limite.



miércoles, 26 de junio de 2013

SQLServer 2008. Importación masiva de datos de un fichero delimitado a una tabla.

Como todos sabréis, y sino os lo digo yo, SQL Server 2008 (en todas sus versiones) nos ofrece un abanico enorme de posibilidades para realizar cualquier cosa que podamos imaginar sobre una base de datos. En este artículo me centrare en insertar grandes volúmenes de datos en una tabla de una tacada. 

Como ya he comentando, tenemos muchísimas posibilidades, pero si los datos están en un fichero externo, es decir, no viene de otra base de datos ya sea en nuestro servidor u otro (enlace al artículo sobre vinculación de servidores), dichas posibilidades se van recortando, aun así, son muchas. Entre ellas y por mi propia experiencia, las que más me gustan son dos:  mediante XML y con ficheros delimitados.

En esta ocasión vamos a explicar como lo haríamos con ficheros delimitados, donde nuevamente, tenemos varias posibilidades, siendo la que explicaré a continuación no la mas rápida (de implementar), pero si la más segura y efectiva. Este proceso sería muy útil a la hora de hacer una importación/exportación de datos.
Teniendo la tabla:
01 CREATE TABLE poetas
02 (
03    CODIGO integer not null PRIMARY KEY,
04    NOMBRE VARCHAR(150) not null,
05    APELLIDOS VARCHAR(150) not null,
06    DIRECCION VARCHAR(150) null,
07    LOCALIDAD VARCHAR(150) null,
08    PROVINCIA VARCHAR(150) null
09 )
Y teniendo un fichero con el siguiente formato: 
01 1|Gustavo Adolfo|Bécquer| Conde de Barajas|Sevilla|Sevilla##
Donde el carácter "|" es el separador de campos, y los caracteres "##" el separador de linea. Además necesitamos un XML con la definición de campos del fichero a usar relacionándolos con los campos y tipos de las columnas de la tabla donde se van a insertar los datos. El formato sería: 

01 <?xml version="1.0"?> 
02 
03 <BCPFORMAT xmlns="http://schemas.microsoft.
04 com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.
05 org/2001/XMLSchema-instance"> 
06 
07 <RECORD> 
08 
09 <FIELD ID="1" xsi:type="CharTerm" TERMINATOR="|"/> 
10 <FIELD ID="2" xsi:type="CharTerm" TERMINATOR="|"/> 
11 <FIELD ID="3" xsi:type="CharTerm" TERMINATOR="|"/> 
12 <FIELD ID="4" xsi:type="CharTerm" TERMINATOR="|"/> 
13 <FIELD ID="5" xsi:type="CharTerm" TERMINATOR="|"/> 
14 <FIELD ID="6" xsi:type="CharTerm" TERMINATOR="##"/> 
15 
16 </RECORD> <ROW> 
17 
18 <COLUMN SOURCE="1" NAME="CODIGO" xsi:type="SQLSMALLINT"/> 
19 <COLUMN SOURCE="2" NAME="NOMBRE" xsi:type="SQLNVARCHAR"/> 
20 <COLUMN SOURCE="3" NAME="APELLIDOS" xsi:type="SQLNVARCHAR"/> 
21 <COLUMN SOURCE="4" NAME="DIRECCION" xsi:type="SQLNVARCHAR"/> 
22 <COLUMN SOURCE="5" NAME="LOCALIDAD" xsi:type="SQLNVARCHAR"/> 
23 <COLUMN SOURCE="6" NAME="PROVINCIA" xsi:type="SQLNVARCHAR"/> 
24 
25 </ROW> </BCPFORMAT> 


Solo nos faltaría ejecutar una instrucción como esta:


01 INSERT INTO poetas(CODIGO, NOMBRE, APELLIDOS, DIRECCION, LOCALIDAD, PROVINCIA) 
02 SELECT  CODIGO, NOMBRE, APELLIDOS, DIRECCION, LOCALIDAD, PROVINCIA
03 FROM OPENROWSET(BULK 'C:\exportacion\poetas.txt', 
04 FORMATFILE='C:\exportacion\poetas.xml' 
05 ) as t1 ;
Aclarar que igual que lo hacemos con una sentencia INSERT, podríamos hacerlo con un UPDATE o un DELETE sin más problemas. También deciros que esta instrucción disparará una sola vez los triggers que tengamos  en la tabla, por lo que deberemos programarlos para que traten el conjunto de datos y no solo un registro.

domingo, 23 de junio de 2013

Exprés: ¿Qué ha indexado google de mi web?

Es muy interesante saber que páginas (y como) tiene google indexadas de nuestra web, o de cualquier otra. Para ello nos ofrece esta utilidad, muy usada en el mundo de SEO. Se trata del comando site:dominio.com. para usarla tan solo tenemos que ir www.google.es y escribir en el buscador site:dominioquequeramosver.loquesea. (También para subdominios)

Nos aparecerán todas las páginas que google tiene indexadas sobre dicho dominio. Con esto podremos comprobar si estan correctas todas nuestras URLs amigables por ejemplo, o si hay algunas páginas que no queremos que google indexe. 

Para limitar la indexación de google, usaremos el fichero robots.txt introduciendo una directiva "Disallow:paginaquenoqueremosqueaparezca" con las URLs que queramos bloquear. También podríamos usar un subdominio, o una carpeta cuyo contenido no queramos que indexe.

Por último, comentar que esta utilidad de google nos da la posibilidad de pasarle parámetros de búsqueda siguiendo a la instrucción de la forma: site:dominioquequeramosver.loquesea palabrasdebusqueda. De esta forma, filtraremos los resultados obteniendo tan solo las páginas donde aparezcan las palabras de búsqueda que le pasamos como parámetro.

miércoles, 19 de junio de 2013

Ejemplo de encriptación de campos de una base de datos de SQL Server 2008 con Clave

Todos las empresas quieren proteger sus datos de terceros, e incluso de sus propios trabajadores. Lo que muchos "jefes" no tienen tan claro es que siempre hay dos niveles de protección... uno físico y uno lógico. De nada sirve poner un sistema de seguridad por software de ultima generación y "super seguro" si cualquiera tiene acceso al disco físico donde se almacenan los datos. Como respuesta a la pregunta, si alguien se lleva mi base de datos, ¿puede acceder a los datos?. La respuesta siempre es SI. Lo único que podemos hacer es ponerlo más difícil.

Por tanto, desde mi punto de vista, lo más importante es tener un sitio seguro donde almacenar los datos y que físicamente  tan sólo personal autorizado puede acceder a ellos. Además hay que complementar esto con una buena seguridad por software que nos evite el máximo número de ataques posible. ¿y si todo esto falla? la solución pasa por encriptar parte o la totalidad de nuestra base de datos, que si bien no es infalible, nuevamente complicamos un poco mas las cosas a "los malos".

Hay varias formas de encriptar una base de datos de SQL Server 2008, una de las más sencillas es la siguiente. Encriptar los campos de las tablas que no queramos que nadie conozca con una clave. Está claro que si perdemos la clave... nos resultará un poco complicado obtener nosotros mismos esos datos, pero como siempre, por "fuerza bruta" se pueden obtener. Por esto decimos, que lo único que conseguiremos es complicar un poco mas las cosas a "los malos". En próximas entradas hablaré de otros métodos de encriptación de las bases de datos de SQL Server 2008. Es importante saber también  que este método de encriptación esta disponible en la versión Express.

Un ejemplo: 

01 create database DBConClave 
02 
03 GO 
04 
05 use DBConClave 
06 
07 GO 
08 
09 create table Clientes 
10 ( 
11 id integer identity primary key, 
12 nombre varchar(100), 
13 apellidos varchar(200), 
14 cif varchar(20), 
15 ccc VARBINARY(8000) -- este es el campo que vamos a cifrar. 
16 ) 
17 
18 GO 
19 
20 -- insertamos un registro con clave 
21 -- es la menor protección pero también la que requiere menos recursos 
22 INSERT INTO Clientes (nombre, apellidos, cif, ccc) 
23 VALUES ('Sandra', 'Matos', '1231231',ENCRYPTBYPASSPHRASE('mipassword','123132131321')) --mispassword es la clave de cifrado 
24 
25 GO 
26 
27 --si hacemos un select normal no podemos obtener el ccc 
28 SELECT * FROM CLientes 
29 
30 
31 --para poder obtener el ccc del cliente deberíamos pasarle también la clave. 
32 SELECT nombre, apellidos, cif, CONVERT(VARCHAR(300), 
33 DECRYPTBYPASSPHRASE('mispassword',ccc)) as ccc 
34 FROM Clientes



sábado, 15 de junio de 2013

Exprés: Crear Base de Datos SQL Server 2008 en cualquier directorio

En SQL Server 2008 las bases de datos se crean por defecto en el directorio que viene configurado, si bien, es posible cambiarlo. Pero, ¿y si queremos almacenar nuestras bases de datos en otra ubicación ?. El script que deberemos utilizar es el siguiente:

01 create database prueba2 
02 on (name = prueba2_dat, filename = 'D:\Databases\prueba2_dat.mdf') 
03 log on (name = prueba2_log, filename = 'D:\Databases\prueba2_log.ldf') 
04 collate modern_spanish_ci_As



Incluso podemos decirle que el directorio de destino sea una carpeta de red (de otro equipo), pero en este caso, deberemos asignar permisos de Control Total en dicha carpeta para el usuario de Windows que inicia el servicio de SQL Server. Esta opción no es recomendable, porque dejamos en manos de la red el tiempo de respuesta que pueda tener nuestra base de datos, con lo que ello conlleva.