SlideShare ist ein Scribd-Unternehmen logo
1 von 66
Downloaden Sie, um offline zu lesen
Proyecto fin de curso
Indice
1.- Introducción
2.- Clúster
Requisitos
Configuración SAN
Instalacion del rol Servicios de archivos y almacenamiento
Configuración del rol Servicios de archivos y almacenamiento
Configuración del DC
Configuración de los equipos del clúster
Instalación del rol de clúster de conmutación por error
Configuración de los destinos iSCSI
Creando el clúster
3.- Base de Datos
Esquema
Usuarios MySQL
Permisos de los usuarios
Disparadores o Triggers
4.- Páginas web
Servidor web
Lenguajes utilizados
PHP
HTML
CSS
Javascript
5.-Ficheros de configuración
5.1 MySQL: my.cnf
5.2 Apache2:
5.2.1. apache2.conf
5.2.2. 000-defaults.conf
5.2.3. defaults-ssl
5.3 PHP: php.ini
6.- Instalación del servidor
7.- Páginas del Proyecto
8.- Secciones de código relevantes
Control de la sesión
Formato de las llamadas a la base de datos
Control de imagenes
Tratamiento de las contraseñas
Enlaces de las fuentes
Botones
Función de la cuenta atrás
10- Auditorias al sistema web
w3af
Nessus
PHPSECINFO
11- Comentarios sobre los clústeres
12.- Comentarios generales
(Indice)
1.- Introducción
A lo largo de este proyecto veremos como hacer un clúster de alta disponibilidad para una
página web que requiere una base de datos, para ello tratare de explicar primero cada componente
del sistema que vamos a utilizar.
"El término clúster (del inglés clúster, "grupo" o "raíz") se aplica a los conjuntos o conglomerados
de computadoras unidos entre sí normalmente por una red de alta velocidad y que se comportan como si
fuesen una única computadora." Clúster Wikipedia
El clúster por lo tanto es lo que nos otorga la alta disponibilidad, lo que significa que si por
algún motivo algún servidor que forma parte del clúster se apaga, esto no nos afectara a la actividad
del servicio ofrecido, debido a que hay varios equipos que están en constante comunicación entre si
para evitar la perdida de información y la caída del servicio.
"Se le llama base de datos a los bancos de información que contienen datos relativos a diversas
temáticas y categorizados de distinta manera, pero que comparten entre sí algún tipo de vínculo o relación
que busca ordenarlos y clasificarlos en conjunto." Base de datos Wikipedia
La base de datos nos ofrecerá un lugar donde guardar toda la información que necesitemos
almacenar y queramos que este disponible para nuestro servicio, como los nombres de los usuarios,
etc.
"Una página web, página electrónica o cyber página,1 2 es un documento o información electrónica
capaz de contener texto, sonido, vídeo, programas, enlaces, imágenes, y muchas otras cosas, adaptada para
la llamada World Wide Web, y que puede ser accedida mediante un navegador. Esta información se
encuentra generalmente en formato HTML o XHTML, y puede proporcionar navegación (acceso) a otras
páginas web mediante enlaces de hipertexto. Las páginas web frecuentemente también incluyen otros
recursos como ser hojas de estilo en cascada, guiones (scripts), imágenes digitales, entre otros." Página web
Wikipedia
La página web sera la interfaz con el usuario, y es necesario que sea accesible en cualquier
momento, por lo que necesitamos que tenga una alta disponibilidad, lo que nos obliga a hacer el
clúster para que eso sea real, además queremos guardar los datos de los usuarios registrados en
algún sitio y ese lugar sera la base de datos.
Este proyecto se divide en 4 apartados que unidos entre si generan un todo, al estar
estrechamente relacionados: como es la configuración y disposición del hardware y de los sistemas
operativos con la generación de un clúster, en un siguiente nivel estaría la base de datos donde
estará toda la información que necesitemos guardar, después vendría la interfaz web que se
relacionaría con el usuario final, y rodeando todo el sistema una capa que se va entrelazando con las
otras que es la seguridad del proyecto, los datos de los usuarios, etc.
A lo largo del documento iremos diseccionando el proyecto de tal manera que podamos ver
como ir creando las distintas partes por separado, y como se van uniendo poco a poco para hacer un
(Indice)
todo.
2.- Clúster
Requisitos:
Windows Windows Server 2008 R2 Datacenter o Enterprise
Windows Server 2012 R2 Datacenter
Escenario:
1 Controlador de Dominio
3 w2008r2 para el clúster
1 w2012r2 para SAN
Conexiones:
1 red interna con el DC:
10.10.1.0/24
1 red interna para los clústeres:
10.10.2.0/24
1 red interna para SAN:
10.10.3.0/24
(Indice)
Configurando el almacenamiento SAN en Windows Server 2012 R2:
Configuración de la MV del servidor SAN:
Este servidor no estará dentro del Dominio
2 discos duros:
1. Disco del sistema: 100 GB
2. Disco del servidor SAN: 400GB
Mínimo de 1 adaptador de red con
conexión a la red interna "red san"
(Indice)
Le asignamos una IP de nuestra red interna "red san", y le cambiamos el nombre al equipo.
(Indice)
Nos aseguramos que el disco este utilizable, sino creamos un nuevo volumen simple.
Una vez realizados estos pasos previos, pasaremos a agregar la funcionalidad iSCSI Target:
1. Vamos a "Agregar roles y características"
(Indice)
2. Aquí nos indica que hace este asistente, "Siguiente".
3. Seleccionamos "Instalación basada en características y roles" y "Siguiente"
4. Escogemos el servidor donde queremos hacer la instalación y “Siguiente”
(Indice)
5. Seleccionamos en “Roles del servidor” dentro de “Servicios de archivos y almacenamiento”
los “Servicios de iSCSI y archivo”, dentro de esta pestaña tenemos que elegir 2, el “Servidor
de archivos” y el “Servidor del destino iSCSI”, en el caso que pinchemos primero en el
servidor de destino iSCSI nos dirá que es necesario el servidor de archivos, y “Siguiente”.
6. En características le damos a “Siguiente”
(Indice)
7. Confirmamos que todo esta correcto e instalamos
8. Una vez instalado pinchamos en “Cerrar”
(Indice)
Una vez instalado el rol, procedemos a configurarlo:
1. Vamos a “Servicios de archivos y de almacenamiento”
2. Seleccionamos “iSCSI”
3. Pinchamos en el enlace al asistente
(Indice)
4. Seleccionamos el disco donde crearemos nuestro almacenamiento iSCSI y “Siguiente”
5. Le asignamos un nombre, a ser posible significativo de su función
(Indice)
6. Asignamos el tamaño del disco y en mi caso le pongo que se expanda dinámicamente y
“Siguiente”
7. Ahora elegimos la opción de “Nuevo destino iSCSI” y “Siguiente”
(Indice)
8. Le ponemos un nombre a nuestro destino SAN y “Siguiente”.
(Indice)
9. Agregamos los iniciadores del servidor SAN, elegimos la opción de identificación por IP.
(Indice)
10. “Siguiente”.
11. Si estamos esta todo bien, le damos a “Crear”.
(Indice)
12. Una vez finalizada la creación cerramos.
13. Ahora continuamos creando el disco quorum, para el clúster, vamos a “Tareas” > “Nuevo
disco virtual iSCSI”
(Indice)
14. Seleccionamos la ubicación del nuevo disco y “Siguiente”
15. Le asignamos un nombre y “Siguiente”
(Indice)
16. Le damos asignamos 10 GB, este disco no necesita tener gran capacidad y “Siguiente”
17. Seleccionamos nuestro destino que hemos creado previamente y “Siguiente”
(Indice)
18. Confirmamos que esta todo correctamente y creamos el disco
19. Cuando finalice cerramos
20. Y podemos ver los 2 discos creados
(Indice)
Configuración del DC:
En el controlador de dominio he agregado los siguientes roles, par una mayor comodidad a lo largo
de las pruebas:
1. Servicios de acceso y directivas de redes, el enrutamiento, para mantener toda la red clúster
dentro de la propia red y simular así la salida a Internet
2. Servidor DHCP, con un ámbito para repartir IPs dinámicamente a los clientes cuando se
hagan las pruebas
3. 1 usuario llamado “clúster” para la administración de los clústeres
Configuración de los equipos de los clústeres, previo a la creación del clúster:
1. Configuramos las IPs y el nombre del equipo de todos los equipos
(Indice)
2. Los agregamos al dominio
Agregaremos la característica de clústeres a todos los equipos:
1. Vamos a Agregar características
(Indice)
2. Seleccionamos Clúster de conmutación por error
3. Pinchamos en “Instalar”
(Indice)
4. Una vez instalada cerramos.
Agregamos el destino iSCSI a nuestros servidores:
1. Vamos al “Iniciador iSCSI”
(Indice)
2. Le damos a “Si”.
3. En la pestaña “Destinos” introducimos la IP de nuestro servidor SAN y pinchamos en
“Conexión rápida...”
(Indice)
4. Seleccionamos el destino y le damos a “Listo”
(Indice)
5. En la pestaña “Volúmenes y dispositivos” pinchamos en “Autoconfigurar” y nos aparecerán
los discos.
(Indice)
6. En la pestaña de “Destinos favoritos” comprobamos que esta nuestro destino y le damos a
“Aceptar”
(Indice)
La primera vez que los usemos tendremos que seguir unos pasos previos para inicializar el disco:
1. Empezamos por ir a la administración de discos y poner el disco “En línea”
2. Después inicializamos el disco
(Indice)
3. Le decimos el tipo de tabla de particiones que queremos:
4. Creamos un “Nuevo volumen simple...” y seguimos el asistente
5. Finalmente debe de tener este aspecto, un disco pequeño para el quorum y el disco de
almacenamiento de datos:
(Indice)
Llegados a este momento debemos de repetir todos los pasos menos la inicialización de los discos
que la hicimos en el primero, pero en el resto hay que ponerlos “En línea” a todos.
Haciendo una pequeña recapitulación de lo que llevamos hecho:
1. Instalado y configurado el DC
2. Instalado y configurado el servidor SAN
3. Instalada la característica de clúster por conmutación por error y configurados e iniciados
los destinos iSCSI
Creando el clúster:
1. Vamos a las características y seleccionamos “Administrador de clústeres” y una vez dentro
pinchamos en “Validar una configuración”
(Indice)
2. Nos informa para que vale el asistente y le damos a “Siguiente”
3. Seleccionamos los equipos con los que queremos crear el clúster
(Indice)
4. Seleccionamos la opción de “Ejecutar todas las pruebas”
5. Confirmamos y le damos a “Siguiente” y esperamos a que realice las pruebas
(Indice)
6. Una vez finalizadas las pruebas revisamos el informe y si todo es correcto pinchamos en
“Crear el clúster ahora con los nodos validados”
7. Aquí nos mostrara lo que hace este nuevo asistente, “Siguiente”
(Indice)
8. Le damos un nombre al clúster y una IP publica para su uso y administración y “Siguiente”
9. Confirmamos y le damos “Siguiente” y esperamos a que se cree el clúster.
(Indice)
10. Una vez terminado, le damos a Finalizar
En este punto tendremos un Clúster de conmutación por error listo para instalarle servicios
Informe de la validación:
1. Aquí vemos que nos da una advertencia, pero que el resto esta todo perfecto
(Indice)
2. La advertencia es sobre los controladores firmados que no se han podido validar
3. Cuando los vemos podemos ver que el motivo es debido a que Windows no reconoce a
VirtualBox como un controlador confiable
(Indice)
(Indice)
3.- Base de Datos
Esquema:
Usuarios MySQL:
Hay dos usuarios de MySQL dedicados en exclusividad al manejo de la base de datos del juego,
estos son “juegophp”, usuario pensado para que lo maneje el motor del juego para actualizar la base
de datos y hacer de nexo entre los usuarios finales del juego y la base de datos, este es un usuario
limitado a lo que es necesario para mover el juego.
Y otro usuario llamado “adminjuego” que es el administrador del juego, que tiene control total
sobre la base de datos de juegophp pero no puede hacer absolutamente nada fuera de su base de
datos.
Permisos de los usuarios:
Permisos del usuario “juegophp” sobre las tablas de la base de datos:
(Indice)
Permisos del usuario “adminjuego”:
Disparadores o Triggers de la base de datos:
(Indice)
4.- Páginas Web
Servidor web:
He decidido elegir Apache web server por varios motivos:
1. Familiaridad, debido al que es el que más he usado, que no el único.
2. Tipo de Licencia, open source : Licencia Apache 2.0
3. Soporte y documentación
Lenguajes utilizados:
• PHP
• HTML
• CSS
• Javascript
PHP:
“Es un lenguaje de 'scripting' de propósito general y de código abierto que está especialmente
pensado para el desarrollo web y que puede ser embebido en páginas HTML.” de php.net
Lo importante del lenguaje PHP es que es del lado del servidor, por lo que su ejecución se realiza en
el servidor y el resultado se envía al cliente.
El echo de que sea un lenguaje de servidor le hace ideal para realizar todo tipo de proyectos web
que queremos que sean más o menos fáciles de implementar debido a la que la curva de aprendizaje
inicialmente es muy fácil y hasta que se complica de verdad hay mucho espacio para empezar
muchos proyectos distintos, en mi caso un juego online.
Además el PHP serán las entrañas del juego, donde se filtraran y gestionaran los datos obtenidos de
los clientes, en gran medida de que nuestro servidor sea o no seguro depende del tipo de
implementación elegida, como el uso de $_POST en lugar de $_GET, etc.
HTML:
“Es un estándar que sirve de referencia para la elaboración de páginas web en sus diferentes
versiones, define una estructura básica y un código para la definición de contenido de una página
web” de Wikipedia
Con el lenguaje HTML lo que hacemos es definir el esqueleto de la interfaz gráfica que el usuario
final recibirá, es lo que le dará uniformidad a nuestro proyecto.
CSS:
“Es un lenguaje usado para definir y crear la presentación de un documento estructurado escrito en
HTML o XML, es el encargado de formular la especificación de las hojas de estilo que servirán de
estándar para los agentes de usuario o navegadores.” de Wikipedia
Usamos CSS para darle al esqueleto del HTML la definición del diseño, y la armonía que todo
proyecto web necesita.
Además las hojas de estilo nos permitan personalizar y jugar con el diseño de la página de manera
dinámica.
(Indice)
Javascript:
“ Es un lenguaje de programación interpretado. Se define como orientado a objetos, basado en
prototipos, imperativo, débilmente tipado y dinámico.” de Wikipedia
Javascript esta orientado en nuestro proyecto a darle vida al contenido del juego en el lado del
cliente. Y generando el dinamismo esperado por el usuario final.
Con él también tendremos a nuestra disposición herramientas de filtrado previo nuestro servidor,
por lo que aunque sigamos filtrando con PHP, esto nos ayudara a evitar llamadas de errores al
servidor por lo que al final es menor carga de trabajo.
5.-Ficheros de configuración
En este apartado veremos como quedan al final los ficheros de configuración, la única diferencia
entre estos ficheros y los reales es que he borrado los comentarios de los mismos.
5.1 MySQL: my.cnf
Ruta del fichero: /etc/mysql/my.cnf
[client]
port = 3306
socket = /var/run/mysqld/mysqld.sock
[mysqld_safe]
socket = /var/run/mysqld/mysqld.sock
nice = 0
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
bind-address = 127.0.0.1
key_buffer = 32M
max_allowed_packet = 16M
thread_stack = 192K
thread_cache_size = 8
myisam-recover = BACKUP
table_cache = 1024
(Indice)
query_cache_limit = 1M
query_cache_size = 32M
log_error = /var/log/mysql/error.log
slow_query_log_file = /var/log/mysql/mysql-slow.log
slow_query_log = 1
long_query_time = 2
expire_logs_days = 10
max_binlog_size = 100M
[mysqldump]
quick
quote-names
max_allowed_packet = 16M
[mysql]
#no-auto-rehash # faster start of mysql but no tab completition
[isamchk]
key_buffer = 16M
!includedir /etc/mysql/conf.d/
5.2 Apache2:
5.2.1. apache2.conf
Ruta del fichero: /etc/apache2/apache2.conf
#ServerRoot "/etc/apache2"
Mutex file:${APACHE_LOCK_DIR} default
PidFile ${APACHE_PID_FILE}
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
HostnameLookups Off
ErrorLog ${APACHE_LOG_DIR}/error.log
(Indice)
LogLevel warn
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
Include ports.conf
<Directory />
Require all denied
Order Deny,Allow
Options None
AllowOverride None
</Directory>
<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/>
DirectoryIndex principal.php
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
AccessFileName .htaccess
<FilesMatch "^.ht">
Require all denied
</FilesMatch>
Header always append X-Frame-Options SAMEORIGIN
LogFormat "%v:%p %h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i""
vhost_combined
LogFormat "%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" combined
LogFormat "%h %l %u %t "%r" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
IncludeOptional conf-enabled/*.conf
IncludeOptional sites-enabled/*.conf
ServerSignature Off
ServerTokens Prod
LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
php_flag allow_url_fopen off
(Indice)
php_value memory_limit 8M
php_value post_max_size 256K
php_value upload_tmp_dir /var/www/html/temp
php_value open_basedir /var/www/html
5.2.2. 000-defaults.conf
Ruta del fichero: /etc/apache2/sites-available/000-default-.conf
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
RewriteEngine on
RewriteCond %{SERVER_PORT} =80
RewriteRule ^(.*) https://%{SERVER_NAME}%{REQUEST_URI}
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
5.2.3. defaults-ssl
Ruta del fichero: /etc/apache2/sites-available/default-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLCertificateFile /etc/ssl/certs/server.crt
SSLCertificateKeyFile /etc/ssl/private/server.key.insecure
#SSLVerifyClient optional
#SSLVerifyDepth 10
SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
<FilesMatch ".(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
BrowserMatch "MSIE [2-6]" 
nokeepalive ssl-unclean-shutdown 
downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
SSLProtocol All -SSLv2 -SSLv3
SSLCompression off
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM
EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256
(Indice)
EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+AESGCM EECDH EDH+AESGCM
EDH+aRSA HIGH !MEDIUM !LOW !aNULL !eNULL !LOW !RC4 !MD5 !EXP !PSK !SRP !
DSS"
ExpiresActive On
ExpiresByType image/gif A432000
ExpiresByType image/jpg A432000
ExpiresByType image/jpeg A432000
ExpiresByType image/png A432000
ExpiresByType image/bmp A432000
ExpiresByType text/css A432000
ExpiresByType text/javascript A432000
AddOutputFilterByType DEFLATE text/html text/plain text/xml
text/css text/javascript application/x-javascript
Header always append X-Frame-Options SAMEORIGIN
</VirtualHost>
</IfModule>
5.3 PHP: php.ini
Ruta del fichero: /etc/php5/apache2/php.ini
[PHP]
engine = On
short_open_tag = Off
asp_tags = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = 17
open_basedir = "/var/www/html"
disable_functions =
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignale
d,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_la
st_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_ge
tpriority,pcntl_setpriority,
disable_classes =
realpath_cache_size = 16k
zend.enable_gc = On
expose_php = Off
max_execution_time = 30
max_input_time = 60
memory_limit = 8M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
(Indice)
html_errors = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 256k
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_tmp_dir =/var/www/html/temp
upload_max_filesize = 2M
max_file_uploads = 20
allow_url_fopen = off
allow_url_include = Off
default_socket_timeout = 60
[CLI Server]
cli_server.color = On
[Date]
[iconv]
[intl]
[sqlite]
[sqlite3]
[Pcre]
[Pdo]
[Pdo_mysql]
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[Phar]
[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = On
[SQL]
sql.safe_mode = Off
(Indice)
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
ibase.dateformat = "%Y-%m-%d"
ibase.timeformat = "%H:%M:%S"
[MySQL]
mysql.allow_local_infile = On
mysql.allow_persistent = On
mysql.cache_size = 2000
mysql.max_persistent = -1
mysql.max_links = -1
mysql.default_port =
mysql.default_socket =
mysql.default_host =
mysql.default_user =
mysql.default_password =
mysql.connect_timeout = 60
mysql.trace_mode = Off
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off
[OCI8]
[PostgreSQL]
pgsql.allow_persistent = On
(Indice)
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[Sybase-CT]
sybct.allow_persistent = On
sybct.max_persistent = -1
sybct.max_links = -1
sybct.min_server_severity = 10
sybct.min_client_severity = 10
[bcmath]
bcmath.scale = 0
[browscap]
[Session]
session.save_handler = files
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 0
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.hash_function = 0
session.hash_bits_per_character = 5
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"
[MSSQL]
mssql.allow_persistent = On
mssql.max_persistent = -1
mssql.max_links = -1
mssql.min_error_severity = 10
mssql.min_message_severity = 10
mssql.compatibility_mode = Off
mssql.secure_connection = Off
[Assertion]
[COM]
(Indice)
[mbstring]
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[sysvshm]
[ldap]
ldap.max_links = -1
[mcrypt]
[dba]
[opcache]
[curl]
[openssl]
6.- Instalación del servidor
1. Instalamos la base de datos MySQL
2. Instalamos el servidor web Apache2
3. Instalamos el motor de PHP
4. Instalamos la interfaz de administracion de PHPMYADMIN
• Instalamos MySQL-server y MySQL-client
• Instalamos Apache2
(Indice)
• Instalamos PHP5, PHP5-MySQL, libapache2-mod-php5
• Instalamos phpmyadmin
• Reiniciamos el servidor por primera vez
Creacción de los certificados ssl/ssh:
Los certificados los generamos para poder probar las funcionalidades de HTTPS que usaremos en el
servidor, pero hay que tener en cuenta que para un servidor en producción, debemos obtener un
certificado de un tercero para que nuestra página sea de total confianza
◦ Paso 1, generamos el primer certificado
◦ Paso 2, generamos el certificado no pass, y le cambiamos los permisos para que solo lo use
root
(Indice)
◦ Paso 3, terminamos el certificado, y los resultante los movemos a las carpetas donde
guardaremos nuestros certificados
Configurando Apache2
Habilitamos el modulo de SSL de Apache y reiniciamos el apache
Si hacemos la prueba ahora, veremos que podemos acceder a la version HTTPS de nuesto servidor
web
Pero esto es solo el principio ya que aun debemos de configurar 2 ficheros enteros para que nuestro
servidor Apache este utilizable. Y Habilitar un par de módulos, que son: rewrite, expires y ssl.
(Indice)
Así que ahora una vez instalado todo, aun no hemos configurado nada, probamos que funcionan y
procedemos a configurar fichero a fichero, y hacer pruebas a lo largo de la configuración para
confirmarnos que todo va bien.
7.- Páginas del proyecto:
1. acceso.html
Página de inicio de Runic Adventures
2. acceso.php
Página de control de acceso al juego
3. combate.php
Página donde se ejecutan los diversos combates de Runic Adventures
4. creaheroe.php
Formulario donde el usuario crea al héroe
5. cuenta.php
Formulario para cambiar los datos de la cuenta
6. enviarmensajes.php
Página de la interfaz y de la gestión de los mensajes enviados
7. fotoheroe.php
Página de gestión de la subida de la imagen del héroe
8. funciones.php
Pagina estándar incluida en todas las demás que contiene las funciones y la plantilla estándar
de la interfaz de Runic Adventures
9. heroe.php
Formulario de personalización del héroe: imagen, nombre y biografía
10. hogar.php
Formulario de selección del equipo, página del inventario
11. juego01.css
Fichero CSS que armoniza la interfaz de Runic Adventures
12. leermensajes.php
Página para la lectura y borrado de los mensajes
13. mensajes.php
Página del menú principal de los mensajes
14. modcuenta.php
Página que genera y controla la petición de los cambios de la cuenta
15. modheroe.php
Página que genera y controla la petición de los cambios del héroe
16. modhogar.php
Página que genera y controla la petición de los cambios del equipo del héroe
17. nuevoheroe.php
Página que genera y controla la creación de un nuevo héroe
18. principal.php
Página principal del juego
19. registro.html
Formulario de creación de un nuevo usuario
20. registro.php
Página que genera y controla la creación de un nuevo usuario
21. salir.php
Página que borra la sesión y desconecta del juego
22. subirlvl.php
Página que genera y controla la petición de subida de nivel del héroe
(Indice)
23. subirnivel.php
Formulario para la subida de nivel del héroe
24. trabajando.php
Página que gestiona la petición de trabajos
25. trabajos.php
Menú de los trabajos disponibles
8.- Secciones de código relevantes:
Control de la sesión:
Normalmente contiene la primera llamada a la base de datos, incluye la llamada al archivo
funciones.php, el header principal del php
***
<?php
if(session_start() && isset($_SESSION['usuario']))
{
$user=trim($_SESSION['usuario']);
$nombreHeroe=$_SESSION['héroe'];
header('Content-Type: text/html; charset=utf-8');
include 'funciones.php';
// Conexión al Servidor
$con=@mysqli_connect('localhost','juegophp','centauro','juegophp');
}
else
{
header("Location: acceso.html");
exit();
}
***
Formato de las llamadas a la base de datos:
***
// Conexión normalmente esta en el control de sesión al principio de la página
$con=@mysqli_connect('localhost','juegophp','centauro','juegophp');
// consulta que se hará a la base de datos
$query = "SELECT * FROM heroes WHERE usuario like '$user'";
// almacenamiento de la consulta realizada
$result = mysqli_query($con, $query);
// guardando los datos de la cunsulta en un array
$héroe = mysqli_fetch_array($result,MYSQLI_BOTH);
***
Control de imágenes subidas por usuarios, resalto este ya que es el que mantiene una imagen por
usuario dentro de nuestro servidor.
***
$query="update heroes set ruta='$rutaDestino' WHERE usuario like '$user' and nombre like
'$nombreHeroe' ";
// Si la ruta del fichero es la misma o es igual que la imagen de base de los usuarios , la sube
if ($héroe[11] == $rutaDestin || $héroe[11] == $base)
{
move_uploaded_file($rutaTemporal,$rutaDestino);
(Indice)
}
else
{
// en cualquier otro caso la renombras y después subes la nueva imagen
rename($héroe[11], $rutaDestino);
move_uploaded_file($rutaTemporal,$rutaDestino);
}
//si todo va bien actualizamos la base de datos y volvemos a la página de heroe.php
if (mysqli_query($con, $query)){
header("Location: heroe.php");
}
else
{
header("Location: heroe.php");
}
***
Tratamiento de las contraseñas dentro del juego:
Encripto la contraseña y la corto antes de guardarla en la base de datos, para mejorar la seguridad de
nuestra base de datos
***
$user=trim( $_POST['usuario'] );
$passw=crypt(trim( $_POST['passw'] ),'$5$rounds=5000$calamaresensutin$');
$passw=substr($passw, 32);
***
Enlaces de las fuentes, esto es una curiosidad, ya que yo al solo servir paginas https, hay que
indicarselo en el link para que las utilice porque sino simplemente no las llama por no ser seguras.
***
<link href='https://fonts.googleapis.com/css?family=Cinzel+Decorative:700' rel='stylesheet'
type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Julius+Sans+One' rel='stylesheet'
type='text/css'>
***
Función que controla los botones de subir o bajar un punto a las características, esta funcionalidad
esta realizada con javascript
***
function addfue(delta) {
var total = eval(subirlvl.fue.value)+eval(subirlvl.des.value)+eval(subirlvl.vit.value)
+eval(subirlvl.def.value);
(Indice)
valor = eval(subirlvl.fue.value);
if (delta == +1)
{
if (total < max)
{
subirlvl.fue.value = eval(valor+delta);
}
}
else
{
if (valor > fuer)
{
subirlvl.fue.value = eval(valor+delta);
}
}
}
// este es el botón en html
<LABEL for="fue">Fuerza: </LABEL>
<br />
<input type="button" value="-" onClick="addfue(-1);">
<input type='text' name='fue' value="10" size="1" />
<input type="button" value="+" onClick="addfue(1);">
***
Función de la cuenta atrás, marca de manera visual para el usuario el tiempo que le queda para
realizar el siguiente trabajo, esta función costo hacerla andar ya que aunque la base esta obtenida de
Internet había que adaptarla al código y a mi sistema de control de tiempos.
***
toYear=<?php echo date('Y',$trabajo_actual[2])?>;
toMonth=<?php echo date('m',$trabajo_actual[2])?>;
toDay=<?php echo date('d',$trabajo_actual[2])?>;
toHour=<?php echo date('H',$trabajo_actual[2])?>;
toMinute=<?php echo date('i',$trabajo_actual[2])?>;
toSecond=<?php echo date('s',$trabajo_actual[2])?>;
function countDown()
{
new_year=0;
new_month=0;
new_day=0;
new_hour=0;
new_minute=0;
new_second=0;
actual_date=new Date();
if(actual_date.getFullYear()>toYear)
(Indice)
{
//si ya nos hemos pasado del año, mostramos los valores a 0
form.second.value=0;
form.minute.value=0;
form.hour.value=0;
form.day.value=0;
form.month.value=0;
form.year.value=0;
}else{
new_second=new_second+toSecond-actual_date.getSeconds();
if(new_second<0)
{
new_second=60+new_second;
new_minute=-1;
}
form.second.value=new_second;
new_minute=new_minute+toMinute-actual_date.getMinutes();
if(new_minute<0)
{
new_minute=60+new_minute;
new_hour=-1;
}
form.minute.value=new_minute;
new_hour=new_hour+toHour-actual_date.getHours();
if(new_hour<0)
{
new_hour=24+new_hour;
new_day=-1;
}
form.hour.value=new_hour;
new_day=new_day+toDay-actual_date.getDate();
if(new_day<0)
{
x=actual_date.getMonth();
if(x==0||x==2||x==4||x==6||x==7||x==9||x==11){new_day=31+new_day;}
if(x==3||x==5||x==8||x==10){new_day=30+new_day;}
if(x==1)
{
//comprobamos si es un año bisiesto...
if(actual_date.getYear()/4-Math.floor(actual_date.getYear()/4)==0)
{
actual_date=29+actual_date;
}else{
actual_date=28+actual_date;
}
}
}
(Indice)
form.day.value=new_day;
new_month=-1;
new_month=new_month+toMonth-actual_date.getMonth();
if(new_month<0)
{
new_month=11+new_month;
new_year=-1;
}
form.month.value=new_month;
new_year=new_year+toYear-actual_date.getFullYear();
if(new_year<0)
{
form.year.value=0;
}else{
form.year.value=new_year;
//vuelve a ejecutar la funcion dentro de 1000 milisegundos = 1 segundo
setTimeout("countDown()",1000);
<?php if ($trabajo_actual == 1)
{
$resta2=($fecha-$trabajo_actual[2])*(-1)*1000;
echo "setTimeout('location.reload(true)',$resta2)";
}
?>
}
}
}
***
9.- Estructura de MySQL, Tablas y Triggers
-- phpMyAdmin SQL Dump
-- version 4.2.7.1
-- http://www.phpmyadmin.net
--
-- Servidor: localhost
-- Tiempo de generación: 19-06-2015 a las 04:35:44
-- Versión del servidor: 5.6.20
-- Versión de PHP: 5.5.15
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
--
-- Base de datos: `juegophp`
--
CREATE DATABASE IF NOT EXISTS `juegophp` DEFAULT CHARACTER SET latin1
COLLATE latin1_swedish_ci;
USE `juegophp`;
(Indice)
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `equipo`
--
DROP TABLE IF EXISTS `equipo`;
CREATE TABLE IF NOT EXISTS `equipo` (
`id_equipo` int(4) NOT NULL,
`nombre` varchar(255) NOT NULL,
`lvl` int(4) NOT NULL,
`fue` int(4) NOT NULL,
`def` int(4) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `heroes`
--
DROP TABLE IF EXISTS `heroes`;
CREATE TABLE IF NOT EXISTS `heroes` (
`usuario` varchar(255) NOT NULL,
`nombre` varchar(255) NOT NULL,
`nivel` int(4) NOT NULL,
`fue` int(4) NOT NULL,
`des` int(4) NOT NULL,
`vit` int(4) NOT NULL,
`def` int(4) NOT NULL,
`equipo` text,
`obj1` int(4) DEFAULT NULL,
`obj2` int(4) DEFAULT NULL,
`exp` int(10) NOT NULL DEFAULT '0',
`ruta` varchar(255) DEFAULT NULL,
`descripcion` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `mensajes`
--
DROP TABLE IF EXISTS `mensajes`;
CREATE TABLE IF NOT EXISTS `mensajes` (
`id_mensaje` int(11) NOT NULL,
`remitente` varchar(255) NOT NULL,
`usuario` varchar(255) NOT NULL,
`fecha` datetime NOT NULL,
(Indice)
`leido` int(1) NOT NULL,
`asunto` varchar(255) NOT NULL,
`mensaje` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=34 ;
--
-- Disparadores `mensajes`
--
DROP TRIGGER IF EXISTS `mensajes_delete`;
DELIMITER //
CREATE TRIGGER `mensajes_delete` BEFORE DELETE ON `mensajes`
FOR EACH ROW BEGIN
-- Insert record into audit table
INSERT INTO mensajes_bk(id_mensaje, remitente, usuario, fecha, leido, asunto, mensaje,
fec_borr) VALUES (old.id_mensaje , old.remitente , old.usuario , old.fecha , old.leido , old.asunto ,
old.mensaje,now());
END
//
DELIMITER ;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `mensajes_bk`
--
DROP TABLE IF EXISTS `mensajes_bk`;
CREATE TABLE IF NOT EXISTS `mensajes_bk` (
`id_mensaje` int(11) NOT NULL,
`remitente` varchar(255) NOT NULL,
`usuario` varchar(255) NOT NULL,
`fecha` datetime NOT NULL,
`leido` int(1) NOT NULL,
`asunto` varchar(255) NOT NULL,
`mensaje` text NOT NULL,
`fec_borr` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=21 ;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `monstruos`
--
DROP TABLE IF EXISTS `monstruos`;
CREATE TABLE IF NOT EXISTS `monstruos` (
`id_monstruo` int(4) NOT NULL,
`nombre` varchar(80) COLLATE utf8_spanish_ci NOT NULL,
`nivel` int(4) NOT NULL,
(Indice)
`fue` int(4) NOT NULL,
`des` int(4) NOT NULL,
`vit` int(4) NOT NULL,
`def` int(4) NOT NULL,
`exp` int(4) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `trabajos`
--
DROP TABLE IF EXISTS `trabajos`;
CREATE TABLE IF NOT EXISTS `trabajos` (
`héroe` varchar(255) NOT NULL,
`id_trabajo` int(2) NOT NULL,
`finalizacion` varchar(80) NOT NULL,
`finalizado` int(2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `trabajos_tipos`
--
DROP TABLE IF EXISTS `trabajos_tipos`;
CREATE TABLE IF NOT EXISTS `trabajos_tipos` (
`id_trabajo` int(2) NOT NULL,
`tiempo` varchar(80) NOT NULL,
`exp` int(5) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `usuarios`
--
DROP TABLE IF EXISTS `usuarios`;
CREATE TABLE IF NOT EXISTS `usuarios` (
`usuario` varchar(255) NOT NULL,
`pass` varchar(255) NOT NULL,
`nombre` varchar(50) NOT NULL,
`apellidos` varchar(100) NOT NULL,
`correo` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Índices para tablas volcadas
(Indice)
--
--
-- Indices de la tabla `equipo`
--
ALTER TABLE `equipo`
ADD PRIMARY KEY (`id_equipo`);
--
-- Indices de la tabla `heroes`
--
ALTER TABLE `heroes`
ADD PRIMARY KEY (`nombre`), ADD KEY `usuario` (`usuario`), ADD KEY `obj1` (`obj1`),
ADD KEY `obj2` (`obj2`);
--
-- Indices de la tabla `mensajes`
--
ALTER TABLE `mensajes`
ADD PRIMARY KEY (`id_mensaje`), ADD KEY `usuario` (`usuario`);
--
-- Indices de la tabla `mensajes_bk`
--
ALTER TABLE `mensajes_bk`
ADD PRIMARY KEY (`id_mensaje`), ADD KEY `usuario` (`usuario`);
--
-- Indices de la tabla `monstruos`
--
ALTER TABLE `monstruos`
ADD PRIMARY KEY (`id_monstruo`);
--
-- Indices de la tabla `trabajos`
--
ALTER TABLE `trabajos`
ADD KEY `id_trabajo` (`id_trabajo`), ADD KEY `héroe` (`héroe`);
--
-- Indices de la tabla `trabajos_tipos`
--
ALTER TABLE `trabajos_tipos`
ADD PRIMARY KEY (`id_trabajo`);
--
-- Indices de la tabla `usuarios`
--
ALTER TABLE `usuarios`
ADD PRIMARY KEY (`usuario`);
(Indice)
--
-- AUTO_INCREMENT de las tablas volcadas
--
--
-- AUTO_INCREMENT de la tabla `mensajes`
--
ALTER TABLE `mensajes`
MODIFY `id_mensaje` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=34;
--
-- AUTO_INCREMENT de la tabla `mensajes_bk`
--
ALTER TABLE `mensajes_bk`
MODIFY `id_mensaje` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=21;
--
-- Restricciones para tablas volcadas
--
--
-- Filtros para la tabla `heroes`
--
ALTER TABLE `heroes`
ADD CONSTRAINT `heroes_ibfk_1` FOREIGN KEY (`usuario`) REFERENCES `usuarios`
(`usuario`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `heroes_ibfk_2` FOREIGN KEY (`obj1`) REFERENCES `equipo`
(`id_equipo`) ON DELETE SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT `heroes_ibfk_3` FOREIGN KEY (`obj2`) REFERENCES `equipo`
(`id_equipo`) ON DELETE SET NULL ON UPDATE CASCADE;
--
-- Filtros para la tabla `mensajes`
--
ALTER TABLE `mensajes`
ADD CONSTRAINT `mensajes_ibfk_1` FOREIGN KEY (`usuario`) REFERENCES `heroes`
(`nombre`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Filtros para la tabla `trabajos`
--
ALTER TABLE `trabajos`
ADD CONSTRAINT `trabajos_ibfk_1` FOREIGN KEY (`id_trabajo`) REFERENCES
`trabajos_tipos` (`id_trabajo`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `trabajos_ibfk_2` FOREIGN KEY (`héroe`) REFERENCES `heroes`
(`nombre`) ON DELETE CASCADE ON UPDATE CASCADE;
(Indice)
10.- Auditorias al sistema web:
w3af:
Este programa me llamo mucho la atención, por su fácil uso y múltiples opciones. Aparte de venir
con herramientas pensadas para la realización de ataques a través de los exploits detectados
Cuenta con una interfaz muy simple, tenemos la opción de elegir el tipo de ataque y donde poner el
objetivo o target
Bien, el tiempo puede depender de muchas cosas, ya sea si la pagina es muy grande o el tipo de
Scan que usaremos, el "fast_scan" no tarda más allá de unos 10 minutos.
En las pestañas de la izquierda podemos ir revisando los resultados y los exploit.
Como conclusión W3af, queda entre la lista de los favoritos en relación a la auditoria y seguridad
web.
Nessus:
“Nessus es un programa de escaneo de vulnerabilidades en diversos sistemas operativos. Consiste
en un daemon, nessusd, que realiza el escaneo en el sistema objetivo, y nessus, el cliente (basado en
consola o gráfico) que muestra el avance e informa sobre el estado de los escaneos. Desde consola
nessus puede ser programado para hacer escaneos programados con cron.
En operación normal, nessus comienza escaneando los puertos con nmap o con su propio
escaneador de puertos para buscar puertos abiertos y después intentar varios exploits para atacarlo.
Las pruebas de vulnerabilidad, disponibles como una larga lista de plugins, son escritos en NASL
(Nessus Attack Scripting Language, Lenguaje de Scripting de Ataque Nessus por sus siglas en
inglés), un lenguaje scripting optimizado para interacciones personalizadas en redes.
(Indice)
Opcionalmente, los resultados del escaneo pueden ser exportados como informes en varios
formatos, como texto plano, XML, HTML, y LaTeX. Los resultados también pueden ser guardados
en una base de conocimiento para referencia en futuros escaneos de vulnerabilidades.
Algunas de las pruebas de vulnerabilidades de Nessus pueden causar que los servicios o sistemas
operativos se corrompan y caigan. El usuario puede evitar esto desactivando "unsafe test" (pruebas
no seguras) antes de escanear.
Actualmente existen dos versiones: "Home" y "Work" Esta última de pago y sin restricciones.”
de Wikipedia
(Indice)
Esta herramienta de auditoria es la más valorada dentro de las auditorias de servicios webs, tiene
una infinidad de plugins para auditar e intentar romper la seguridad de la web.
Si nos fijamos en la imagen hay 3 advertencias en amarillo, que lo que vienen a decir es que el
certificado autofirmado no es una vulnerabilidad como tal pero no se merece la confianza necesaria,
y el otro es debido a la permisividad de compatibilidad con los usuarios con navegadores más
antiguos.
PHPSECINFO:
Este programa nos sirve para auditar el php.ini y la configuración general de php de nuestro
servidor. Es aplicación que muestra la información sobre la seguridad de un código PHP y nos
sugiere ideas para mejorarlo. Ahora hay que dejar claro que no audita propiamente nuestro código
sino que nos ayuda a configurar los cimientos donde se apoyara nuestro código.
11.- Comentarios sobre los clústeres
Quería dedicar un apartado a los clústeres aunque finalmente no lo haya implementado, por
las razones que veremos más adelante, ya que me parece de las tecnologías más importantes dentro
de cualquier sistema informático que sea importante, ya que una buena clusterización nos permite
tanto dar alta disponibilidad como mantener los datos a salvo en caso de falla de alguno de los
sistemas.
¿Por qué no los he introducido al final?
Pese a qué me parece una parte muy importante de un servicio que fuese grande, y debido ha
que aunque hacer funcionar un clúster en Windows es fácil para ciertos servicios como puede ser el
DFS de Windows que con apenas unos clics lo tienes funcionando no pasa lo mismo cuando quieres
implementar una aplicación como MySQL, Apache2 o el servicio de PHP, y lo que más me molesto
ya que yo en un principio quería un proyecto que manejase apache y mysql, pero decidí probar a
(Indice)
clusterizar IIS y MSSQL y el resultado fue el mismo, que llegado cierto punto de la clusterización
de estos servicios especiales requieren una configuración de los registros de Windows en cada nodo,
y tienen que ser ademas de todos los cambios generados por dichas aplicaciones
¿Por qué no Linux?
Al principio no quería usar Linux por 2 motivos principales, la implementación de un clúster
básico de Windows es muy sencilla, cosa que no se puede decir lo mismo de las distribuciones de
Linux que he manejado y la segunda era que ya sabía hacer un clúster de Windows.
Después de mucha investigación he concluido que cierto es que para ciertas operaciones
como mantener un servidor DFS y otros servicios concretos de Windows puede resultar muy
cómodo un clúster en Windows, pero para proyectos webs, es indiscutiblemente mejor y más fácil
de implementar al final pese a que hay que usar de medía 3 programas distintos, y un mínimo de 3
equipos, al final una vez bien configurado un clúster de Linux realiza una muy buena labor ya que
por un lado mantiene sincronizada toda la información como que además pueden funcionar como
equipos en solitario, una opción que para ciertas situaciones puede ser muy importante.
Pero el motivo por el que pese haberme documentado sobre estos clústeres llegue a la
conclusión que si quería un clúster en Linux, que a su vez fuese seguro, no me daba tiempo material
a realizarlo, ya que como muchas cosas en Linux pese a que se puede hacer todo hay que hacerlo
sin ningún tipo de asistente ni script rápido por lo que para hacer un clúster que no sea funcional al
100% he decidido apartarlo del proyecto.
12.- Comentarios generales.
En mi opinión personal este proyecto me ha ayudado a ver una serie de cosas como la
clusterización en Linux o la importancia de usar $_POST en lugar de $_GET para el tratamiento de
las peticiones sean seguras a la hora del desarrollo web, la infinidad de opciones que nos da php, y
su facilidad de uso e implementación.
También me ha generado inquietudes sobre la seguridad en la web y la facilidad que hay de
generar vulnerabilidades en un servidor que este mal configurado, pese a que se que para terminar
de fortificar este servidor habría que hacer una buena configuración de IPTables.
El proyecto en general me ha gustado mucho al realizarlo debido a que en el fondo se que es
la base de muchos juegos online, obviamente aun le faltaría mucho trabajo para poder llevarlo a un
ambiente de producción pero se que son unos buenos cimientos sobre los que poder empezar a
trabajar algo de un nivel más serio.
(Indice)

Weitere ähnliche Inhalte

Was ist angesagt?

Creación de certificados digitales con openssl CA local
Creación de certificados digitales con openssl CA localCreación de certificados digitales con openssl CA local
Creación de certificados digitales con openssl CA localHenry Cristian Cuesta Vega
 
Instalación Windows Server 2012 - Instalación y configuración de active direc...
Instalación Windows Server 2012 - Instalación y configuración de active direc...Instalación Windows Server 2012 - Instalación y configuración de active direc...
Instalación Windows Server 2012 - Instalación y configuración de active direc...Victor Escamilla
 
Manual instalacion sql_server
Manual instalacion sql_serverManual instalacion sql_server
Manual instalacion sql_serverJhon_Marjorie
 
Windows server 2012 jose luis
Windows server 2012 jose luisWindows server 2012 jose luis
Windows server 2012 jose luisyanez1814
 
Windows Server 2008 (Maquina Virtual)
Windows Server 2008 (Maquina Virtual)Windows Server 2008 (Maquina Virtual)
Windows Server 2008 (Maquina Virtual)Héctor Neri
 
Luis manuel negrete olivares 6 f
Luis manuel negrete olivares 6 fLuis manuel negrete olivares 6 f
Luis manuel negrete olivares 6 fackroes
 
Configuracion de un servidor de archivos
Configuracion de un servidor de archivosConfiguracion de un servidor de archivos
Configuracion de un servidor de archivosElim Aqp
 
Manual de instalación y administración de active directory en windows server ...
Manual de instalación y administración de active directory en windows server ...Manual de instalación y administración de active directory en windows server ...
Manual de instalación y administración de active directory en windows server ...camilaml
 
Configuración del Servicio
Configuración del ServicioConfiguración del Servicio
Configuración del Servicioeduenlasiberia
 
Añadir un cliente Ubuntu a un Dominio 2008 Server
Añadir un cliente Ubuntu a un Dominio 2008 ServerAñadir un cliente Ubuntu a un Dominio 2008 Server
Añadir un cliente Ubuntu a un Dominio 2008 Servereduenlasiberia
 
Novedades windows server 2012
Novedades windows server 2012Novedades windows server 2012
Novedades windows server 2012ErnestoSF
 
Instalación e Introducción básica de Windows Server 2012
Instalación e Introducción básica de Windows Server 2012Instalación e Introducción básica de Windows Server 2012
Instalación e Introducción básica de Windows Server 2012Moisés Elías Araya
 
Curso, manual, tutorial windows 2003 server
Curso, manual, tutorial   windows 2003 serverCurso, manual, tutorial   windows 2003 server
Curso, manual, tutorial windows 2003 servercharly0885
 
Instalacion Weblogic Server 11g Linux
Instalacion Weblogic Server 11g LinuxInstalacion Weblogic Server 11g Linux
Instalacion Weblogic Server 11g LinuxMoisés Elías Araya
 

Was ist angesagt? (19)

Creación de certificados digitales con openssl CA local
Creación de certificados digitales con openssl CA localCreación de certificados digitales con openssl CA local
Creación de certificados digitales con openssl CA local
 
Instalación Windows Server 2012 - Instalación y configuración de active direc...
Instalación Windows Server 2012 - Instalación y configuración de active direc...Instalación Windows Server 2012 - Instalación y configuración de active direc...
Instalación Windows Server 2012 - Instalación y configuración de active direc...
 
Usuarios dominio-2008
Usuarios dominio-2008Usuarios dominio-2008
Usuarios dominio-2008
 
Manual instalacion sql_server
Manual instalacion sql_serverManual instalacion sql_server
Manual instalacion sql_server
 
Windows server 2012 jose luis
Windows server 2012 jose luisWindows server 2012 jose luis
Windows server 2012 jose luis
 
Windows Server 2008 (Maquina Virtual)
Windows Server 2008 (Maquina Virtual)Windows Server 2008 (Maquina Virtual)
Windows Server 2008 (Maquina Virtual)
 
Manual de instalacion
Manual de instalacionManual de instalacion
Manual de instalacion
 
Luis manuel negrete olivares 6 f
Luis manuel negrete olivares 6 fLuis manuel negrete olivares 6 f
Luis manuel negrete olivares 6 f
 
Configuracion de un servidor de archivos
Configuracion de un servidor de archivosConfiguracion de un servidor de archivos
Configuracion de un servidor de archivos
 
Manual de instalación y administración de active directory en windows server ...
Manual de instalación y administración de active directory en windows server ...Manual de instalación y administración de active directory en windows server ...
Manual de instalación y administración de active directory en windows server ...
 
Configuración del Servicio
Configuración del ServicioConfiguración del Servicio
Configuración del Servicio
 
Instalar Oracle 11g R2 CentOS 6.4
Instalar Oracle 11g R2 CentOS 6.4Instalar Oracle 11g R2 CentOS 6.4
Instalar Oracle 11g R2 CentOS 6.4
 
DHCP
DHCPDHCP
DHCP
 
Añadir un cliente Ubuntu a un Dominio 2008 Server
Añadir un cliente Ubuntu a un Dominio 2008 ServerAñadir un cliente Ubuntu a un Dominio 2008 Server
Añadir un cliente Ubuntu a un Dominio 2008 Server
 
Novedades windows server 2012
Novedades windows server 2012Novedades windows server 2012
Novedades windows server 2012
 
Instalación e Introducción básica de Windows Server 2012
Instalación e Introducción básica de Windows Server 2012Instalación e Introducción básica de Windows Server 2012
Instalación e Introducción básica de Windows Server 2012
 
Curso, manual, tutorial windows 2003 server
Curso, manual, tutorial   windows 2003 serverCurso, manual, tutorial   windows 2003 server
Curso, manual, tutorial windows 2003 server
 
Reporte-Instalando Windows Server 2012
Reporte-Instalando Windows Server 2012Reporte-Instalando Windows Server 2012
Reporte-Instalando Windows Server 2012
 
Instalacion Weblogic Server 11g Linux
Instalacion Weblogic Server 11g LinuxInstalacion Weblogic Server 11g Linux
Instalacion Weblogic Server 11g Linux
 

Ähnlich wie Configuración de un clúster de alta disponibilidad para una página web

Introduccion A Windows Server 2003
Introduccion A Windows Server 2003Introduccion A Windows Server 2003
Introduccion A Windows Server 2003RiChArD13
 
Introduccion A Windows Server 2003
Introduccion A Windows Server 2003Introduccion A Windows Server 2003
Introduccion A Windows Server 2003guestde4364
 
Manual para-instalar-oracle-database-11 g-r2-en-centos-6
Manual para-instalar-oracle-database-11 g-r2-en-centos-6Manual para-instalar-oracle-database-11 g-r2-en-centos-6
Manual para-instalar-oracle-database-11 g-r2-en-centos-6shac Rob
 
Presentación OpenStack Comunidad Venezuela
Presentación OpenStack Comunidad VenezuelaPresentación OpenStack Comunidad Venezuela
Presentación OpenStack Comunidad VenezuelaEnder Mujica Diaz
 
Los sistemas operativos de Red
Los sistemas operativos de Red Los sistemas operativos de Red
Los sistemas operativos de Red ANDINO2017
 
Como configrar webdav como unidad de red en alfresco
Como configrar webdav como unidad de red en alfrescoComo configrar webdav como unidad de red en alfresco
Como configrar webdav como unidad de red en alfrescoJose Antonio Albalat Almenara
 
trabajo de cesar farfan
trabajo de cesar farfantrabajo de cesar farfan
trabajo de cesar farfanyacilahenry
 
Manual de configuracion de proxy SQUID
Manual de configuracion de proxy SQUIDManual de configuracion de proxy SQUID
Manual de configuracion de proxy SQUIDAndres Ldño
 
Qué es exactamente un sistema cluster
Qué es exactamente un sistema clusterQué es exactamente un sistema cluster
Qué es exactamente un sistema clusterJuan Manuel Torres
 

Ähnlich wie Configuración de un clúster de alta disponibilidad para una página web (20)

Introduccion A Windows Server 2003
Introduccion A Windows Server 2003Introduccion A Windows Server 2003
Introduccion A Windows Server 2003
 
Introduccion A Windows Server 2003
Introduccion A Windows Server 2003Introduccion A Windows Server 2003
Introduccion A Windows Server 2003
 
Paso a paso zenoss 2.5
Paso a paso zenoss  2.5Paso a paso zenoss  2.5
Paso a paso zenoss 2.5
 
Bulma 441
Bulma 441Bulma 441
Bulma 441
 
Manual para-instalar-oracle-database-11 g-r2-en-centos-6
Manual para-instalar-oracle-database-11 g-r2-en-centos-6Manual para-instalar-oracle-database-11 g-r2-en-centos-6
Manual para-instalar-oracle-database-11 g-r2-en-centos-6
 
Presentación OpenStack Comunidad Venezuela
Presentación OpenStack Comunidad VenezuelaPresentación OpenStack Comunidad Venezuela
Presentación OpenStack Comunidad Venezuela
 
Los sistemas operativos de Red
Los sistemas operativos de Red Los sistemas operativos de Red
Los sistemas operativos de Red
 
Antologia de taller de base de datos 1 26
Antologia de taller de base de datos 1 26Antologia de taller de base de datos 1 26
Antologia de taller de base de datos 1 26
 
Actividad n 5.3 http ftp
Actividad n 5.3 http ftpActividad n 5.3 http ftp
Actividad n 5.3 http ftp
 
Actividad n 5.3 http ftp
Actividad n 5.3 http ftpActividad n 5.3 http ftp
Actividad n 5.3 http ftp
 
Como configrar webdav como unidad de red en alfresco
Como configrar webdav como unidad de red en alfrescoComo configrar webdav como unidad de red en alfresco
Como configrar webdav como unidad de red en alfresco
 
QUE ES SERVER
QUE ES SERVERQUE ES SERVER
QUE ES SERVER
 
trabajo de cesar farfan
trabajo de cesar farfantrabajo de cesar farfan
trabajo de cesar farfan
 
Manual de configuracion de proxy SQUID
Manual de configuracion de proxy SQUIDManual de configuracion de proxy SQUID
Manual de configuracion de proxy SQUID
 
Qué es exactamente un sistema cluster
Qué es exactamente un sistema clusterQué es exactamente un sistema cluster
Qué es exactamente un sistema cluster
 
Manual de uso_de_squid
Manual de uso_de_squidManual de uso_de_squid
Manual de uso_de_squid
 
Servidor HTTP IIS
Servidor HTTP IISServidor HTTP IIS
Servidor HTTP IIS
 
Proyecto Integrado ASIR
Proyecto Integrado ASIRProyecto Integrado ASIR
Proyecto Integrado ASIR
 
Sqlite
SqliteSqlite
Sqlite
 
Server 2008
Server 2008Server 2008
Server 2008
 

Kürzlich hochgeladen

Red Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del PerúRed Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del PerúCEFERINO DELGADO FLORES
 
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024u20211198540
 
Herramientas que posibilitan la información y la investigación.pdf
Herramientas que posibilitan la información y la investigación.pdfHerramientas que posibilitan la información y la investigación.pdf
Herramientas que posibilitan la información y la investigación.pdfKarinaCambero3
 
TALLER DE ANALISIS SOLUCION PART 2 (1)-1.docx
TALLER DE ANALISIS SOLUCION  PART 2 (1)-1.docxTALLER DE ANALISIS SOLUCION  PART 2 (1)-1.docx
TALLER DE ANALISIS SOLUCION PART 2 (1)-1.docxobandopaula444
 
Actividades de computación para alumnos de preescolar
Actividades de computación para alumnos de preescolarActividades de computación para alumnos de preescolar
Actividades de computación para alumnos de preescolar24roberto21
 
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdfBetianaJuarez1
 
CommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersCommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersIván López Martín
 
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxLAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxAlexander López
 
Modelo de Presentacion Feria Robotica Educativa 2024 - Versión3.pptx
Modelo de Presentacion Feria Robotica Educativa 2024 - Versión3.pptxModelo de Presentacion Feria Robotica Educativa 2024 - Versión3.pptx
Modelo de Presentacion Feria Robotica Educativa 2024 - Versión3.pptxtjcesar1
 
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docxPLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docxhasbleidit
 
Trabajo de tecnología excel avanzado.pdf
Trabajo de tecnología excel avanzado.pdfTrabajo de tecnología excel avanzado.pdf
Trabajo de tecnología excel avanzado.pdfedepmariaperez
 
Análisis de los artefactos (nintendo NES)
Análisis de los artefactos (nintendo NES)Análisis de los artefactos (nintendo NES)
Análisis de los artefactos (nintendo NES)JuanStevenTrujilloCh
 
Viguetas Pretensadas en concreto armado
Viguetas Pretensadas  en concreto armadoViguetas Pretensadas  en concreto armado
Viguetas Pretensadas en concreto armadob7fwtwtfxf
 
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptxLINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptxkimontey
 
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptxHugoGutierrez99
 
Slideshare y Scribd - Noli Cubillan Gerencia
Slideshare y Scribd - Noli Cubillan GerenciaSlideshare y Scribd - Noli Cubillan Gerencia
Slideshare y Scribd - Noli Cubillan Gerenciacubillannoly
 
La tecnología y su impacto en la sociedad
La tecnología y su impacto en la sociedadLa tecnología y su impacto en la sociedad
La tecnología y su impacto en la sociedadEduardoSantiagoSegov
 
David_Gallegos - tarea de la sesión 11.pptx
David_Gallegos - tarea de la sesión 11.pptxDavid_Gallegos - tarea de la sesión 11.pptx
David_Gallegos - tarea de la sesión 11.pptxDAVIDROBERTOGALLEGOS
 
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).pptLUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).pptchaverriemily794
 

Kürzlich hochgeladen (20)

Red Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del PerúRed Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
 
El camino a convertirse en Microsoft MVP
El camino a convertirse en Microsoft MVPEl camino a convertirse en Microsoft MVP
El camino a convertirse en Microsoft MVP
 
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
 
Herramientas que posibilitan la información y la investigación.pdf
Herramientas que posibilitan la información y la investigación.pdfHerramientas que posibilitan la información y la investigación.pdf
Herramientas que posibilitan la información y la investigación.pdf
 
TALLER DE ANALISIS SOLUCION PART 2 (1)-1.docx
TALLER DE ANALISIS SOLUCION  PART 2 (1)-1.docxTALLER DE ANALISIS SOLUCION  PART 2 (1)-1.docx
TALLER DE ANALISIS SOLUCION PART 2 (1)-1.docx
 
Actividades de computación para alumnos de preescolar
Actividades de computación para alumnos de preescolarActividades de computación para alumnos de preescolar
Actividades de computación para alumnos de preescolar
 
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
 
CommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersCommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 Testcontainers
 
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxLAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
 
Modelo de Presentacion Feria Robotica Educativa 2024 - Versión3.pptx
Modelo de Presentacion Feria Robotica Educativa 2024 - Versión3.pptxModelo de Presentacion Feria Robotica Educativa 2024 - Versión3.pptx
Modelo de Presentacion Feria Robotica Educativa 2024 - Versión3.pptx
 
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docxPLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
 
Trabajo de tecnología excel avanzado.pdf
Trabajo de tecnología excel avanzado.pdfTrabajo de tecnología excel avanzado.pdf
Trabajo de tecnología excel avanzado.pdf
 
Análisis de los artefactos (nintendo NES)
Análisis de los artefactos (nintendo NES)Análisis de los artefactos (nintendo NES)
Análisis de los artefactos (nintendo NES)
 
Viguetas Pretensadas en concreto armado
Viguetas Pretensadas  en concreto armadoViguetas Pretensadas  en concreto armado
Viguetas Pretensadas en concreto armado
 
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptxLINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
 
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
 
Slideshare y Scribd - Noli Cubillan Gerencia
Slideshare y Scribd - Noli Cubillan GerenciaSlideshare y Scribd - Noli Cubillan Gerencia
Slideshare y Scribd - Noli Cubillan Gerencia
 
La tecnología y su impacto en la sociedad
La tecnología y su impacto en la sociedadLa tecnología y su impacto en la sociedad
La tecnología y su impacto en la sociedad
 
David_Gallegos - tarea de la sesión 11.pptx
David_Gallegos - tarea de la sesión 11.pptxDavid_Gallegos - tarea de la sesión 11.pptx
David_Gallegos - tarea de la sesión 11.pptx
 
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).pptLUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
 

Configuración de un clúster de alta disponibilidad para una página web

  • 1. Proyecto fin de curso Indice 1.- Introducción 2.- Clúster Requisitos Configuración SAN Instalacion del rol Servicios de archivos y almacenamiento Configuración del rol Servicios de archivos y almacenamiento Configuración del DC Configuración de los equipos del clúster Instalación del rol de clúster de conmutación por error Configuración de los destinos iSCSI Creando el clúster 3.- Base de Datos Esquema Usuarios MySQL Permisos de los usuarios Disparadores o Triggers 4.- Páginas web Servidor web Lenguajes utilizados PHP HTML CSS Javascript 5.-Ficheros de configuración 5.1 MySQL: my.cnf 5.2 Apache2: 5.2.1. apache2.conf 5.2.2. 000-defaults.conf 5.2.3. defaults-ssl 5.3 PHP: php.ini 6.- Instalación del servidor 7.- Páginas del Proyecto 8.- Secciones de código relevantes Control de la sesión Formato de las llamadas a la base de datos Control de imagenes Tratamiento de las contraseñas Enlaces de las fuentes Botones Función de la cuenta atrás 10- Auditorias al sistema web w3af Nessus PHPSECINFO 11- Comentarios sobre los clústeres 12.- Comentarios generales (Indice)
  • 2. 1.- Introducción A lo largo de este proyecto veremos como hacer un clúster de alta disponibilidad para una página web que requiere una base de datos, para ello tratare de explicar primero cada componente del sistema que vamos a utilizar. "El término clúster (del inglés clúster, "grupo" o "raíz") se aplica a los conjuntos o conglomerados de computadoras unidos entre sí normalmente por una red de alta velocidad y que se comportan como si fuesen una única computadora." Clúster Wikipedia El clúster por lo tanto es lo que nos otorga la alta disponibilidad, lo que significa que si por algún motivo algún servidor que forma parte del clúster se apaga, esto no nos afectara a la actividad del servicio ofrecido, debido a que hay varios equipos que están en constante comunicación entre si para evitar la perdida de información y la caída del servicio. "Se le llama base de datos a los bancos de información que contienen datos relativos a diversas temáticas y categorizados de distinta manera, pero que comparten entre sí algún tipo de vínculo o relación que busca ordenarlos y clasificarlos en conjunto." Base de datos Wikipedia La base de datos nos ofrecerá un lugar donde guardar toda la información que necesitemos almacenar y queramos que este disponible para nuestro servicio, como los nombres de los usuarios, etc. "Una página web, página electrónica o cyber página,1 2 es un documento o información electrónica capaz de contener texto, sonido, vídeo, programas, enlaces, imágenes, y muchas otras cosas, adaptada para la llamada World Wide Web, y que puede ser accedida mediante un navegador. Esta información se encuentra generalmente en formato HTML o XHTML, y puede proporcionar navegación (acceso) a otras páginas web mediante enlaces de hipertexto. Las páginas web frecuentemente también incluyen otros recursos como ser hojas de estilo en cascada, guiones (scripts), imágenes digitales, entre otros." Página web Wikipedia La página web sera la interfaz con el usuario, y es necesario que sea accesible en cualquier momento, por lo que necesitamos que tenga una alta disponibilidad, lo que nos obliga a hacer el clúster para que eso sea real, además queremos guardar los datos de los usuarios registrados en algún sitio y ese lugar sera la base de datos. Este proyecto se divide en 4 apartados que unidos entre si generan un todo, al estar estrechamente relacionados: como es la configuración y disposición del hardware y de los sistemas operativos con la generación de un clúster, en un siguiente nivel estaría la base de datos donde estará toda la información que necesitemos guardar, después vendría la interfaz web que se relacionaría con el usuario final, y rodeando todo el sistema una capa que se va entrelazando con las otras que es la seguridad del proyecto, los datos de los usuarios, etc. A lo largo del documento iremos diseccionando el proyecto de tal manera que podamos ver como ir creando las distintas partes por separado, y como se van uniendo poco a poco para hacer un (Indice)
  • 3. todo. 2.- Clúster Requisitos: Windows Windows Server 2008 R2 Datacenter o Enterprise Windows Server 2012 R2 Datacenter Escenario: 1 Controlador de Dominio 3 w2008r2 para el clúster 1 w2012r2 para SAN Conexiones: 1 red interna con el DC: 10.10.1.0/24 1 red interna para los clústeres: 10.10.2.0/24 1 red interna para SAN: 10.10.3.0/24 (Indice)
  • 4. Configurando el almacenamiento SAN en Windows Server 2012 R2: Configuración de la MV del servidor SAN: Este servidor no estará dentro del Dominio 2 discos duros: 1. Disco del sistema: 100 GB 2. Disco del servidor SAN: 400GB Mínimo de 1 adaptador de red con conexión a la red interna "red san" (Indice)
  • 5. Le asignamos una IP de nuestra red interna "red san", y le cambiamos el nombre al equipo. (Indice)
  • 6. Nos aseguramos que el disco este utilizable, sino creamos un nuevo volumen simple. Una vez realizados estos pasos previos, pasaremos a agregar la funcionalidad iSCSI Target: 1. Vamos a "Agregar roles y características" (Indice)
  • 7. 2. Aquí nos indica que hace este asistente, "Siguiente". 3. Seleccionamos "Instalación basada en características y roles" y "Siguiente" 4. Escogemos el servidor donde queremos hacer la instalación y “Siguiente” (Indice)
  • 8. 5. Seleccionamos en “Roles del servidor” dentro de “Servicios de archivos y almacenamiento” los “Servicios de iSCSI y archivo”, dentro de esta pestaña tenemos que elegir 2, el “Servidor de archivos” y el “Servidor del destino iSCSI”, en el caso que pinchemos primero en el servidor de destino iSCSI nos dirá que es necesario el servidor de archivos, y “Siguiente”. 6. En características le damos a “Siguiente” (Indice)
  • 9. 7. Confirmamos que todo esta correcto e instalamos 8. Una vez instalado pinchamos en “Cerrar” (Indice)
  • 10. Una vez instalado el rol, procedemos a configurarlo: 1. Vamos a “Servicios de archivos y de almacenamiento” 2. Seleccionamos “iSCSI” 3. Pinchamos en el enlace al asistente (Indice)
  • 11. 4. Seleccionamos el disco donde crearemos nuestro almacenamiento iSCSI y “Siguiente” 5. Le asignamos un nombre, a ser posible significativo de su función (Indice)
  • 12. 6. Asignamos el tamaño del disco y en mi caso le pongo que se expanda dinámicamente y “Siguiente” 7. Ahora elegimos la opción de “Nuevo destino iSCSI” y “Siguiente” (Indice)
  • 13. 8. Le ponemos un nombre a nuestro destino SAN y “Siguiente”. (Indice)
  • 14. 9. Agregamos los iniciadores del servidor SAN, elegimos la opción de identificación por IP. (Indice)
  • 15. 10. “Siguiente”. 11. Si estamos esta todo bien, le damos a “Crear”. (Indice)
  • 16. 12. Una vez finalizada la creación cerramos. 13. Ahora continuamos creando el disco quorum, para el clúster, vamos a “Tareas” > “Nuevo disco virtual iSCSI” (Indice)
  • 17. 14. Seleccionamos la ubicación del nuevo disco y “Siguiente” 15. Le asignamos un nombre y “Siguiente” (Indice)
  • 18. 16. Le damos asignamos 10 GB, este disco no necesita tener gran capacidad y “Siguiente” 17. Seleccionamos nuestro destino que hemos creado previamente y “Siguiente” (Indice)
  • 19. 18. Confirmamos que esta todo correctamente y creamos el disco 19. Cuando finalice cerramos 20. Y podemos ver los 2 discos creados (Indice)
  • 20. Configuración del DC: En el controlador de dominio he agregado los siguientes roles, par una mayor comodidad a lo largo de las pruebas: 1. Servicios de acceso y directivas de redes, el enrutamiento, para mantener toda la red clúster dentro de la propia red y simular así la salida a Internet 2. Servidor DHCP, con un ámbito para repartir IPs dinámicamente a los clientes cuando se hagan las pruebas 3. 1 usuario llamado “clúster” para la administración de los clústeres Configuración de los equipos de los clústeres, previo a la creación del clúster: 1. Configuramos las IPs y el nombre del equipo de todos los equipos (Indice)
  • 21. 2. Los agregamos al dominio Agregaremos la característica de clústeres a todos los equipos: 1. Vamos a Agregar características (Indice)
  • 22. 2. Seleccionamos Clúster de conmutación por error 3. Pinchamos en “Instalar” (Indice)
  • 23. 4. Una vez instalada cerramos. Agregamos el destino iSCSI a nuestros servidores: 1. Vamos al “Iniciador iSCSI” (Indice)
  • 24. 2. Le damos a “Si”. 3. En la pestaña “Destinos” introducimos la IP de nuestro servidor SAN y pinchamos en “Conexión rápida...” (Indice)
  • 25. 4. Seleccionamos el destino y le damos a “Listo” (Indice)
  • 26. 5. En la pestaña “Volúmenes y dispositivos” pinchamos en “Autoconfigurar” y nos aparecerán los discos. (Indice)
  • 27. 6. En la pestaña de “Destinos favoritos” comprobamos que esta nuestro destino y le damos a “Aceptar” (Indice)
  • 28. La primera vez que los usemos tendremos que seguir unos pasos previos para inicializar el disco: 1. Empezamos por ir a la administración de discos y poner el disco “En línea” 2. Después inicializamos el disco (Indice)
  • 29. 3. Le decimos el tipo de tabla de particiones que queremos: 4. Creamos un “Nuevo volumen simple...” y seguimos el asistente 5. Finalmente debe de tener este aspecto, un disco pequeño para el quorum y el disco de almacenamiento de datos: (Indice)
  • 30. Llegados a este momento debemos de repetir todos los pasos menos la inicialización de los discos que la hicimos en el primero, pero en el resto hay que ponerlos “En línea” a todos. Haciendo una pequeña recapitulación de lo que llevamos hecho: 1. Instalado y configurado el DC 2. Instalado y configurado el servidor SAN 3. Instalada la característica de clúster por conmutación por error y configurados e iniciados los destinos iSCSI Creando el clúster: 1. Vamos a las características y seleccionamos “Administrador de clústeres” y una vez dentro pinchamos en “Validar una configuración” (Indice)
  • 31. 2. Nos informa para que vale el asistente y le damos a “Siguiente” 3. Seleccionamos los equipos con los que queremos crear el clúster (Indice)
  • 32. 4. Seleccionamos la opción de “Ejecutar todas las pruebas” 5. Confirmamos y le damos a “Siguiente” y esperamos a que realice las pruebas (Indice)
  • 33. 6. Una vez finalizadas las pruebas revisamos el informe y si todo es correcto pinchamos en “Crear el clúster ahora con los nodos validados” 7. Aquí nos mostrara lo que hace este nuevo asistente, “Siguiente” (Indice)
  • 34. 8. Le damos un nombre al clúster y una IP publica para su uso y administración y “Siguiente” 9. Confirmamos y le damos “Siguiente” y esperamos a que se cree el clúster. (Indice)
  • 35. 10. Una vez terminado, le damos a Finalizar En este punto tendremos un Clúster de conmutación por error listo para instalarle servicios Informe de la validación: 1. Aquí vemos que nos da una advertencia, pero que el resto esta todo perfecto (Indice)
  • 36. 2. La advertencia es sobre los controladores firmados que no se han podido validar 3. Cuando los vemos podemos ver que el motivo es debido a que Windows no reconoce a VirtualBox como un controlador confiable (Indice)
  • 38. 3.- Base de Datos Esquema: Usuarios MySQL: Hay dos usuarios de MySQL dedicados en exclusividad al manejo de la base de datos del juego, estos son “juegophp”, usuario pensado para que lo maneje el motor del juego para actualizar la base de datos y hacer de nexo entre los usuarios finales del juego y la base de datos, este es un usuario limitado a lo que es necesario para mover el juego. Y otro usuario llamado “adminjuego” que es el administrador del juego, que tiene control total sobre la base de datos de juegophp pero no puede hacer absolutamente nada fuera de su base de datos. Permisos de los usuarios: Permisos del usuario “juegophp” sobre las tablas de la base de datos: (Indice)
  • 39. Permisos del usuario “adminjuego”: Disparadores o Triggers de la base de datos: (Indice)
  • 40. 4.- Páginas Web Servidor web: He decidido elegir Apache web server por varios motivos: 1. Familiaridad, debido al que es el que más he usado, que no el único. 2. Tipo de Licencia, open source : Licencia Apache 2.0 3. Soporte y documentación Lenguajes utilizados: • PHP • HTML • CSS • Javascript PHP: “Es un lenguaje de 'scripting' de propósito general y de código abierto que está especialmente pensado para el desarrollo web y que puede ser embebido en páginas HTML.” de php.net Lo importante del lenguaje PHP es que es del lado del servidor, por lo que su ejecución se realiza en el servidor y el resultado se envía al cliente. El echo de que sea un lenguaje de servidor le hace ideal para realizar todo tipo de proyectos web que queremos que sean más o menos fáciles de implementar debido a la que la curva de aprendizaje inicialmente es muy fácil y hasta que se complica de verdad hay mucho espacio para empezar muchos proyectos distintos, en mi caso un juego online. Además el PHP serán las entrañas del juego, donde se filtraran y gestionaran los datos obtenidos de los clientes, en gran medida de que nuestro servidor sea o no seguro depende del tipo de implementación elegida, como el uso de $_POST en lugar de $_GET, etc. HTML: “Es un estándar que sirve de referencia para la elaboración de páginas web en sus diferentes versiones, define una estructura básica y un código para la definición de contenido de una página web” de Wikipedia Con el lenguaje HTML lo que hacemos es definir el esqueleto de la interfaz gráfica que el usuario final recibirá, es lo que le dará uniformidad a nuestro proyecto. CSS: “Es un lenguaje usado para definir y crear la presentación de un documento estructurado escrito en HTML o XML, es el encargado de formular la especificación de las hojas de estilo que servirán de estándar para los agentes de usuario o navegadores.” de Wikipedia Usamos CSS para darle al esqueleto del HTML la definición del diseño, y la armonía que todo proyecto web necesita. Además las hojas de estilo nos permitan personalizar y jugar con el diseño de la página de manera dinámica. (Indice)
  • 41. Javascript: “ Es un lenguaje de programación interpretado. Se define como orientado a objetos, basado en prototipos, imperativo, débilmente tipado y dinámico.” de Wikipedia Javascript esta orientado en nuestro proyecto a darle vida al contenido del juego en el lado del cliente. Y generando el dinamismo esperado por el usuario final. Con él también tendremos a nuestra disposición herramientas de filtrado previo nuestro servidor, por lo que aunque sigamos filtrando con PHP, esto nos ayudara a evitar llamadas de errores al servidor por lo que al final es menor carga de trabajo. 5.-Ficheros de configuración En este apartado veremos como quedan al final los ficheros de configuración, la única diferencia entre estos ficheros y los reales es que he borrado los comentarios de los mismos. 5.1 MySQL: my.cnf Ruta del fichero: /etc/mysql/my.cnf [client] port = 3306 socket = /var/run/mysqld/mysqld.sock [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking bind-address = 127.0.0.1 key_buffer = 32M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8 myisam-recover = BACKUP table_cache = 1024 (Indice)
  • 42. query_cache_limit = 1M query_cache_size = 32M log_error = /var/log/mysql/error.log slow_query_log_file = /var/log/mysql/mysql-slow.log slow_query_log = 1 long_query_time = 2 expire_logs_days = 10 max_binlog_size = 100M [mysqldump] quick quote-names max_allowed_packet = 16M [mysql] #no-auto-rehash # faster start of mysql but no tab completition [isamchk] key_buffer = 16M !includedir /etc/mysql/conf.d/ 5.2 Apache2: 5.2.1. apache2.conf Ruta del fichero: /etc/apache2/apache2.conf #ServerRoot "/etc/apache2" Mutex file:${APACHE_LOCK_DIR} default PidFile ${APACHE_PID_FILE} Timeout 300 KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 5 User ${APACHE_RUN_USER} Group ${APACHE_RUN_GROUP} HostnameLookups Off ErrorLog ${APACHE_LOG_DIR}/error.log (Indice)
  • 43. LogLevel warn IncludeOptional mods-enabled/*.load IncludeOptional mods-enabled/*.conf Include ports.conf <Directory /> Require all denied Order Deny,Allow Options None AllowOverride None </Directory> <Directory /usr/share> AllowOverride None Require all granted </Directory> <Directory /var/www/> DirectoryIndex principal.php Options FollowSymLinks AllowOverride None Require all granted </Directory> AccessFileName .htaccess <FilesMatch "^.ht"> Require all denied </FilesMatch> Header always append X-Frame-Options SAMEORIGIN LogFormat "%v:%p %h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" vhost_combined LogFormat "%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"" combined LogFormat "%h %l %u %t "%r" %>s %O" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent IncludeOptional conf-enabled/*.conf IncludeOptional sites-enabled/*.conf ServerSignature Off ServerTokens Prod LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so php_flag allow_url_fopen off (Indice)
  • 44. php_value memory_limit 8M php_value post_max_size 256K php_value upload_tmp_dir /var/www/html/temp php_value open_basedir /var/www/html 5.2.2. 000-defaults.conf Ruta del fichero: /etc/apache2/sites-available/000-default-.conf <VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www/html RewriteEngine on RewriteCond %{SERVER_PORT} =80 RewriteRule ^(.*) https://%{SERVER_NAME}%{REQUEST_URI} ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> 5.2.3. defaults-ssl Ruta del fichero: /etc/apache2/sites-available/default-ssl.conf <IfModule mod_ssl.c> <VirtualHost _default_:443> ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLEngine on SSLCertificateFile /etc/ssl/certs/server.crt SSLCertificateKeyFile /etc/ssl/private/server.key.insecure #SSLVerifyClient optional #SSLVerifyDepth 10 SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire <FilesMatch ".(cgi|shtml|phtml|php)$"> SSLOptions +StdEnvVars </FilesMatch> <Directory /usr/lib/cgi-bin> SSLOptions +StdEnvVars </Directory> BrowserMatch "MSIE [2-6]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0 BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown SSLProtocol All -SSLv2 -SSLv3 SSLCompression off Header set Strict-Transport-Security "max-age=31536000; includeSubDomains" SSLHonorCipherOrder on SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 (Indice)
  • 45. EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+AESGCM EECDH EDH+AESGCM EDH+aRSA HIGH !MEDIUM !LOW !aNULL !eNULL !LOW !RC4 !MD5 !EXP !PSK !SRP ! DSS" ExpiresActive On ExpiresByType image/gif A432000 ExpiresByType image/jpg A432000 ExpiresByType image/jpeg A432000 ExpiresByType image/png A432000 ExpiresByType image/bmp A432000 ExpiresByType text/css A432000 ExpiresByType text/javascript A432000 AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript Header always append X-Frame-Options SAMEORIGIN </VirtualHost> </IfModule> 5.3 PHP: php.ini Ruta del fichero: /etc/php5/apache2/php.ini [PHP] engine = On short_open_tag = Off asp_tags = Off precision = 14 output_buffering = 4096 zlib.output_compression = Off implicit_flush = Off unserialize_callback_func = serialize_precision = 17 open_basedir = "/var/www/html" disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignale d,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_la st_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_ge tpriority,pcntl_setpriority, disable_classes = realpath_cache_size = 16k zend.enable_gc = On expose_php = Off max_execution_time = 30 max_input_time = 60 memory_limit = 8M error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT display_errors = Off display_startup_errors = Off log_errors = On log_errors_max_len = 1024 ignore_repeated_errors = Off ignore_repeated_source = Off report_memleaks = On track_errors = Off (Indice)
  • 46. html_errors = On variables_order = "GPCS" request_order = "GP" register_argc_argv = Off auto_globals_jit = On post_max_size = 256k auto_prepend_file = auto_append_file = default_mimetype = "text/html" default_charset = "UTF-8" doc_root = user_dir = enable_dl = Off file_uploads = On upload_tmp_dir =/var/www/html/temp upload_max_filesize = 2M max_file_uploads = 20 allow_url_fopen = off allow_url_include = Off default_socket_timeout = 60 [CLI Server] cli_server.color = On [Date] [iconv] [intl] [sqlite] [sqlite3] [Pcre] [Pdo] [Pdo_mysql] pdo_mysql.cache_size = 2000 pdo_mysql.default_socket= [Phar] [mail function] SMTP = localhost smtp_port = 25 mail.add_x_header = On [SQL] sql.safe_mode = Off (Indice)
  • 47. [ODBC] odbc.allow_persistent = On odbc.check_persistent = On odbc.max_persistent = -1 odbc.max_links = -1 odbc.defaultlrl = 4096 odbc.defaultbinmode = 1 [Interbase] ibase.allow_persistent = 1 ibase.max_persistent = -1 ibase.max_links = -1 ibase.timestampformat = "%Y-%m-%d %H:%M:%S" ibase.dateformat = "%Y-%m-%d" ibase.timeformat = "%H:%M:%S" [MySQL] mysql.allow_local_infile = On mysql.allow_persistent = On mysql.cache_size = 2000 mysql.max_persistent = -1 mysql.max_links = -1 mysql.default_port = mysql.default_socket = mysql.default_host = mysql.default_user = mysql.default_password = mysql.connect_timeout = 60 mysql.trace_mode = Off [MySQLi] mysqli.max_persistent = -1 mysqli.allow_persistent = On mysqli.max_links = -1 mysqli.cache_size = 2000 mysqli.default_port = 3306 mysqli.default_socket = mysqli.default_host = mysqli.default_user = mysqli.default_pw = mysqli.reconnect = Off [mysqlnd] mysqlnd.collect_statistics = On mysqlnd.collect_memory_statistics = Off [OCI8] [PostgreSQL] pgsql.allow_persistent = On (Indice)
  • 48. pgsql.auto_reset_persistent = Off pgsql.max_persistent = -1 pgsql.max_links = -1 pgsql.ignore_notice = 0 pgsql.log_notice = 0 [Sybase-CT] sybct.allow_persistent = On sybct.max_persistent = -1 sybct.max_links = -1 sybct.min_server_severity = 10 sybct.min_client_severity = 10 [bcmath] bcmath.scale = 0 [browscap] [Session] session.save_handler = files session.use_only_cookies = 1 session.name = PHPSESSID session.auto_start = 0 session.cookie_lifetime = 0 session.cookie_path = / session.cookie_domain = session.cookie_httponly = session.serialize_handler = php session.gc_probability = 0 session.gc_divisor = 1000 session.gc_maxlifetime = 1440 session.referer_check = session.cache_limiter = nocache session.cache_expire = 180 session.hash_function = 0 session.hash_bits_per_character = 5 url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" [MSSQL] mssql.allow_persistent = On mssql.max_persistent = -1 mssql.max_links = -1 mssql.min_error_severity = 10 mssql.min_message_severity = 10 mssql.compatibility_mode = Off mssql.secure_connection = Off [Assertion] [COM] (Indice)
  • 49. [mbstring] [Tidy] tidy.clean_output = Off [soap] soap.wsdl_cache_enabled=1 soap.wsdl_cache_dir="/tmp" soap.wsdl_cache_ttl=86400 soap.wsdl_cache_limit = 5 [sysvshm] [ldap] ldap.max_links = -1 [mcrypt] [dba] [opcache] [curl] [openssl] 6.- Instalación del servidor 1. Instalamos la base de datos MySQL 2. Instalamos el servidor web Apache2 3. Instalamos el motor de PHP 4. Instalamos la interfaz de administracion de PHPMYADMIN • Instalamos MySQL-server y MySQL-client • Instalamos Apache2 (Indice)
  • 50. • Instalamos PHP5, PHP5-MySQL, libapache2-mod-php5 • Instalamos phpmyadmin • Reiniciamos el servidor por primera vez Creacción de los certificados ssl/ssh: Los certificados los generamos para poder probar las funcionalidades de HTTPS que usaremos en el servidor, pero hay que tener en cuenta que para un servidor en producción, debemos obtener un certificado de un tercero para que nuestra página sea de total confianza ◦ Paso 1, generamos el primer certificado ◦ Paso 2, generamos el certificado no pass, y le cambiamos los permisos para que solo lo use root (Indice)
  • 51. ◦ Paso 3, terminamos el certificado, y los resultante los movemos a las carpetas donde guardaremos nuestros certificados Configurando Apache2 Habilitamos el modulo de SSL de Apache y reiniciamos el apache Si hacemos la prueba ahora, veremos que podemos acceder a la version HTTPS de nuesto servidor web Pero esto es solo el principio ya que aun debemos de configurar 2 ficheros enteros para que nuestro servidor Apache este utilizable. Y Habilitar un par de módulos, que son: rewrite, expires y ssl. (Indice)
  • 52. Así que ahora una vez instalado todo, aun no hemos configurado nada, probamos que funcionan y procedemos a configurar fichero a fichero, y hacer pruebas a lo largo de la configuración para confirmarnos que todo va bien. 7.- Páginas del proyecto: 1. acceso.html Página de inicio de Runic Adventures 2. acceso.php Página de control de acceso al juego 3. combate.php Página donde se ejecutan los diversos combates de Runic Adventures 4. creaheroe.php Formulario donde el usuario crea al héroe 5. cuenta.php Formulario para cambiar los datos de la cuenta 6. enviarmensajes.php Página de la interfaz y de la gestión de los mensajes enviados 7. fotoheroe.php Página de gestión de la subida de la imagen del héroe 8. funciones.php Pagina estándar incluida en todas las demás que contiene las funciones y la plantilla estándar de la interfaz de Runic Adventures 9. heroe.php Formulario de personalización del héroe: imagen, nombre y biografía 10. hogar.php Formulario de selección del equipo, página del inventario 11. juego01.css Fichero CSS que armoniza la interfaz de Runic Adventures 12. leermensajes.php Página para la lectura y borrado de los mensajes 13. mensajes.php Página del menú principal de los mensajes 14. modcuenta.php Página que genera y controla la petición de los cambios de la cuenta 15. modheroe.php Página que genera y controla la petición de los cambios del héroe 16. modhogar.php Página que genera y controla la petición de los cambios del equipo del héroe 17. nuevoheroe.php Página que genera y controla la creación de un nuevo héroe 18. principal.php Página principal del juego 19. registro.html Formulario de creación de un nuevo usuario 20. registro.php Página que genera y controla la creación de un nuevo usuario 21. salir.php Página que borra la sesión y desconecta del juego 22. subirlvl.php Página que genera y controla la petición de subida de nivel del héroe (Indice)
  • 53. 23. subirnivel.php Formulario para la subida de nivel del héroe 24. trabajando.php Página que gestiona la petición de trabajos 25. trabajos.php Menú de los trabajos disponibles 8.- Secciones de código relevantes: Control de la sesión: Normalmente contiene la primera llamada a la base de datos, incluye la llamada al archivo funciones.php, el header principal del php *** <?php if(session_start() && isset($_SESSION['usuario'])) { $user=trim($_SESSION['usuario']); $nombreHeroe=$_SESSION['héroe']; header('Content-Type: text/html; charset=utf-8'); include 'funciones.php'; // Conexión al Servidor $con=@mysqli_connect('localhost','juegophp','centauro','juegophp'); } else { header("Location: acceso.html"); exit(); } *** Formato de las llamadas a la base de datos: *** // Conexión normalmente esta en el control de sesión al principio de la página $con=@mysqli_connect('localhost','juegophp','centauro','juegophp'); // consulta que se hará a la base de datos $query = "SELECT * FROM heroes WHERE usuario like '$user'"; // almacenamiento de la consulta realizada $result = mysqli_query($con, $query); // guardando los datos de la cunsulta en un array $héroe = mysqli_fetch_array($result,MYSQLI_BOTH); *** Control de imágenes subidas por usuarios, resalto este ya que es el que mantiene una imagen por usuario dentro de nuestro servidor. *** $query="update heroes set ruta='$rutaDestino' WHERE usuario like '$user' and nombre like '$nombreHeroe' "; // Si la ruta del fichero es la misma o es igual que la imagen de base de los usuarios , la sube if ($héroe[11] == $rutaDestin || $héroe[11] == $base) { move_uploaded_file($rutaTemporal,$rutaDestino); (Indice)
  • 54. } else { // en cualquier otro caso la renombras y después subes la nueva imagen rename($héroe[11], $rutaDestino); move_uploaded_file($rutaTemporal,$rutaDestino); } //si todo va bien actualizamos la base de datos y volvemos a la página de heroe.php if (mysqli_query($con, $query)){ header("Location: heroe.php"); } else { header("Location: heroe.php"); } *** Tratamiento de las contraseñas dentro del juego: Encripto la contraseña y la corto antes de guardarla en la base de datos, para mejorar la seguridad de nuestra base de datos *** $user=trim( $_POST['usuario'] ); $passw=crypt(trim( $_POST['passw'] ),'$5$rounds=5000$calamaresensutin$'); $passw=substr($passw, 32); *** Enlaces de las fuentes, esto es una curiosidad, ya que yo al solo servir paginas https, hay que indicarselo en el link para que las utilice porque sino simplemente no las llama por no ser seguras. *** <link href='https://fonts.googleapis.com/css?family=Cinzel+Decorative:700' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Julius+Sans+One' rel='stylesheet' type='text/css'> *** Función que controla los botones de subir o bajar un punto a las características, esta funcionalidad esta realizada con javascript *** function addfue(delta) { var total = eval(subirlvl.fue.value)+eval(subirlvl.des.value)+eval(subirlvl.vit.value) +eval(subirlvl.def.value); (Indice)
  • 55. valor = eval(subirlvl.fue.value); if (delta == +1) { if (total < max) { subirlvl.fue.value = eval(valor+delta); } } else { if (valor > fuer) { subirlvl.fue.value = eval(valor+delta); } } } // este es el botón en html <LABEL for="fue">Fuerza: </LABEL> <br /> <input type="button" value="-" onClick="addfue(-1);"> <input type='text' name='fue' value="10" size="1" /> <input type="button" value="+" onClick="addfue(1);"> *** Función de la cuenta atrás, marca de manera visual para el usuario el tiempo que le queda para realizar el siguiente trabajo, esta función costo hacerla andar ya que aunque la base esta obtenida de Internet había que adaptarla al código y a mi sistema de control de tiempos. *** toYear=<?php echo date('Y',$trabajo_actual[2])?>; toMonth=<?php echo date('m',$trabajo_actual[2])?>; toDay=<?php echo date('d',$trabajo_actual[2])?>; toHour=<?php echo date('H',$trabajo_actual[2])?>; toMinute=<?php echo date('i',$trabajo_actual[2])?>; toSecond=<?php echo date('s',$trabajo_actual[2])?>; function countDown() { new_year=0; new_month=0; new_day=0; new_hour=0; new_minute=0; new_second=0; actual_date=new Date(); if(actual_date.getFullYear()>toYear) (Indice)
  • 56. { //si ya nos hemos pasado del año, mostramos los valores a 0 form.second.value=0; form.minute.value=0; form.hour.value=0; form.day.value=0; form.month.value=0; form.year.value=0; }else{ new_second=new_second+toSecond-actual_date.getSeconds(); if(new_second<0) { new_second=60+new_second; new_minute=-1; } form.second.value=new_second; new_minute=new_minute+toMinute-actual_date.getMinutes(); if(new_minute<0) { new_minute=60+new_minute; new_hour=-1; } form.minute.value=new_minute; new_hour=new_hour+toHour-actual_date.getHours(); if(new_hour<0) { new_hour=24+new_hour; new_day=-1; } form.hour.value=new_hour; new_day=new_day+toDay-actual_date.getDate(); if(new_day<0) { x=actual_date.getMonth(); if(x==0||x==2||x==4||x==6||x==7||x==9||x==11){new_day=31+new_day;} if(x==3||x==5||x==8||x==10){new_day=30+new_day;} if(x==1) { //comprobamos si es un año bisiesto... if(actual_date.getYear()/4-Math.floor(actual_date.getYear()/4)==0) { actual_date=29+actual_date; }else{ actual_date=28+actual_date; } } } (Indice)
  • 57. form.day.value=new_day; new_month=-1; new_month=new_month+toMonth-actual_date.getMonth(); if(new_month<0) { new_month=11+new_month; new_year=-1; } form.month.value=new_month; new_year=new_year+toYear-actual_date.getFullYear(); if(new_year<0) { form.year.value=0; }else{ form.year.value=new_year; //vuelve a ejecutar la funcion dentro de 1000 milisegundos = 1 segundo setTimeout("countDown()",1000); <?php if ($trabajo_actual == 1) { $resta2=($fecha-$trabajo_actual[2])*(-1)*1000; echo "setTimeout('location.reload(true)',$resta2)"; } ?> } } } *** 9.- Estructura de MySQL, Tablas y Triggers -- phpMyAdmin SQL Dump -- version 4.2.7.1 -- http://www.phpmyadmin.net -- -- Servidor: localhost -- Tiempo de generación: 19-06-2015 a las 04:35:44 -- Versión del servidor: 5.6.20 -- Versión de PHP: 5.5.15 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; -- -- Base de datos: `juegophp` -- CREATE DATABASE IF NOT EXISTS `juegophp` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci; USE `juegophp`; (Indice)
  • 58. -- -------------------------------------------------------- -- -- Estructura de tabla para la tabla `equipo` -- DROP TABLE IF EXISTS `equipo`; CREATE TABLE IF NOT EXISTS `equipo` ( `id_equipo` int(4) NOT NULL, `nombre` varchar(255) NOT NULL, `lvl` int(4) NOT NULL, `fue` int(4) NOT NULL, `def` int(4) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- -- Estructura de tabla para la tabla `heroes` -- DROP TABLE IF EXISTS `heroes`; CREATE TABLE IF NOT EXISTS `heroes` ( `usuario` varchar(255) NOT NULL, `nombre` varchar(255) NOT NULL, `nivel` int(4) NOT NULL, `fue` int(4) NOT NULL, `des` int(4) NOT NULL, `vit` int(4) NOT NULL, `def` int(4) NOT NULL, `equipo` text, `obj1` int(4) DEFAULT NULL, `obj2` int(4) DEFAULT NULL, `exp` int(10) NOT NULL DEFAULT '0', `ruta` varchar(255) DEFAULT NULL, `descripcion` text NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- -- Estructura de tabla para la tabla `mensajes` -- DROP TABLE IF EXISTS `mensajes`; CREATE TABLE IF NOT EXISTS `mensajes` ( `id_mensaje` int(11) NOT NULL, `remitente` varchar(255) NOT NULL, `usuario` varchar(255) NOT NULL, `fecha` datetime NOT NULL, (Indice)
  • 59. `leido` int(1) NOT NULL, `asunto` varchar(255) NOT NULL, `mensaje` text NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=34 ; -- -- Disparadores `mensajes` -- DROP TRIGGER IF EXISTS `mensajes_delete`; DELIMITER // CREATE TRIGGER `mensajes_delete` BEFORE DELETE ON `mensajes` FOR EACH ROW BEGIN -- Insert record into audit table INSERT INTO mensajes_bk(id_mensaje, remitente, usuario, fecha, leido, asunto, mensaje, fec_borr) VALUES (old.id_mensaje , old.remitente , old.usuario , old.fecha , old.leido , old.asunto , old.mensaje,now()); END // DELIMITER ; -- -------------------------------------------------------- -- -- Estructura de tabla para la tabla `mensajes_bk` -- DROP TABLE IF EXISTS `mensajes_bk`; CREATE TABLE IF NOT EXISTS `mensajes_bk` ( `id_mensaje` int(11) NOT NULL, `remitente` varchar(255) NOT NULL, `usuario` varchar(255) NOT NULL, `fecha` datetime NOT NULL, `leido` int(1) NOT NULL, `asunto` varchar(255) NOT NULL, `mensaje` text NOT NULL, `fec_borr` datetime NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=21 ; -- -------------------------------------------------------- -- -- Estructura de tabla para la tabla `monstruos` -- DROP TABLE IF EXISTS `monstruos`; CREATE TABLE IF NOT EXISTS `monstruos` ( `id_monstruo` int(4) NOT NULL, `nombre` varchar(80) COLLATE utf8_spanish_ci NOT NULL, `nivel` int(4) NOT NULL, (Indice)
  • 60. `fue` int(4) NOT NULL, `des` int(4) NOT NULL, `vit` int(4) NOT NULL, `def` int(4) NOT NULL, `exp` int(4) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci; -- -------------------------------------------------------- -- -- Estructura de tabla para la tabla `trabajos` -- DROP TABLE IF EXISTS `trabajos`; CREATE TABLE IF NOT EXISTS `trabajos` ( `héroe` varchar(255) NOT NULL, `id_trabajo` int(2) NOT NULL, `finalizacion` varchar(80) NOT NULL, `finalizado` int(2) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- -- Estructura de tabla para la tabla `trabajos_tipos` -- DROP TABLE IF EXISTS `trabajos_tipos`; CREATE TABLE IF NOT EXISTS `trabajos_tipos` ( `id_trabajo` int(2) NOT NULL, `tiempo` varchar(80) NOT NULL, `exp` int(5) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- -- Estructura de tabla para la tabla `usuarios` -- DROP TABLE IF EXISTS `usuarios`; CREATE TABLE IF NOT EXISTS `usuarios` ( `usuario` varchar(255) NOT NULL, `pass` varchar(255) NOT NULL, `nombre` varchar(50) NOT NULL, `apellidos` varchar(100) NOT NULL, `correo` varchar(100) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Índices para tablas volcadas (Indice)
  • 61. -- -- -- Indices de la tabla `equipo` -- ALTER TABLE `equipo` ADD PRIMARY KEY (`id_equipo`); -- -- Indices de la tabla `heroes` -- ALTER TABLE `heroes` ADD PRIMARY KEY (`nombre`), ADD KEY `usuario` (`usuario`), ADD KEY `obj1` (`obj1`), ADD KEY `obj2` (`obj2`); -- -- Indices de la tabla `mensajes` -- ALTER TABLE `mensajes` ADD PRIMARY KEY (`id_mensaje`), ADD KEY `usuario` (`usuario`); -- -- Indices de la tabla `mensajes_bk` -- ALTER TABLE `mensajes_bk` ADD PRIMARY KEY (`id_mensaje`), ADD KEY `usuario` (`usuario`); -- -- Indices de la tabla `monstruos` -- ALTER TABLE `monstruos` ADD PRIMARY KEY (`id_monstruo`); -- -- Indices de la tabla `trabajos` -- ALTER TABLE `trabajos` ADD KEY `id_trabajo` (`id_trabajo`), ADD KEY `héroe` (`héroe`); -- -- Indices de la tabla `trabajos_tipos` -- ALTER TABLE `trabajos_tipos` ADD PRIMARY KEY (`id_trabajo`); -- -- Indices de la tabla `usuarios` -- ALTER TABLE `usuarios` ADD PRIMARY KEY (`usuario`); (Indice)
  • 62. -- -- AUTO_INCREMENT de las tablas volcadas -- -- -- AUTO_INCREMENT de la tabla `mensajes` -- ALTER TABLE `mensajes` MODIFY `id_mensaje` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=34; -- -- AUTO_INCREMENT de la tabla `mensajes_bk` -- ALTER TABLE `mensajes_bk` MODIFY `id_mensaje` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=21; -- -- Restricciones para tablas volcadas -- -- -- Filtros para la tabla `heroes` -- ALTER TABLE `heroes` ADD CONSTRAINT `heroes_ibfk_1` FOREIGN KEY (`usuario`) REFERENCES `usuarios` (`usuario`) ON DELETE CASCADE ON UPDATE CASCADE, ADD CONSTRAINT `heroes_ibfk_2` FOREIGN KEY (`obj1`) REFERENCES `equipo` (`id_equipo`) ON DELETE SET NULL ON UPDATE CASCADE, ADD CONSTRAINT `heroes_ibfk_3` FOREIGN KEY (`obj2`) REFERENCES `equipo` (`id_equipo`) ON DELETE SET NULL ON UPDATE CASCADE; -- -- Filtros para la tabla `mensajes` -- ALTER TABLE `mensajes` ADD CONSTRAINT `mensajes_ibfk_1` FOREIGN KEY (`usuario`) REFERENCES `heroes` (`nombre`) ON DELETE CASCADE ON UPDATE CASCADE; -- -- Filtros para la tabla `trabajos` -- ALTER TABLE `trabajos` ADD CONSTRAINT `trabajos_ibfk_1` FOREIGN KEY (`id_trabajo`) REFERENCES `trabajos_tipos` (`id_trabajo`) ON DELETE CASCADE ON UPDATE CASCADE, ADD CONSTRAINT `trabajos_ibfk_2` FOREIGN KEY (`héroe`) REFERENCES `heroes` (`nombre`) ON DELETE CASCADE ON UPDATE CASCADE; (Indice)
  • 63. 10.- Auditorias al sistema web: w3af: Este programa me llamo mucho la atención, por su fácil uso y múltiples opciones. Aparte de venir con herramientas pensadas para la realización de ataques a través de los exploits detectados Cuenta con una interfaz muy simple, tenemos la opción de elegir el tipo de ataque y donde poner el objetivo o target Bien, el tiempo puede depender de muchas cosas, ya sea si la pagina es muy grande o el tipo de Scan que usaremos, el "fast_scan" no tarda más allá de unos 10 minutos. En las pestañas de la izquierda podemos ir revisando los resultados y los exploit. Como conclusión W3af, queda entre la lista de los favoritos en relación a la auditoria y seguridad web. Nessus: “Nessus es un programa de escaneo de vulnerabilidades en diversos sistemas operativos. Consiste en un daemon, nessusd, que realiza el escaneo en el sistema objetivo, y nessus, el cliente (basado en consola o gráfico) que muestra el avance e informa sobre el estado de los escaneos. Desde consola nessus puede ser programado para hacer escaneos programados con cron. En operación normal, nessus comienza escaneando los puertos con nmap o con su propio escaneador de puertos para buscar puertos abiertos y después intentar varios exploits para atacarlo. Las pruebas de vulnerabilidad, disponibles como una larga lista de plugins, son escritos en NASL (Nessus Attack Scripting Language, Lenguaje de Scripting de Ataque Nessus por sus siglas en inglés), un lenguaje scripting optimizado para interacciones personalizadas en redes. (Indice)
  • 64. Opcionalmente, los resultados del escaneo pueden ser exportados como informes en varios formatos, como texto plano, XML, HTML, y LaTeX. Los resultados también pueden ser guardados en una base de conocimiento para referencia en futuros escaneos de vulnerabilidades. Algunas de las pruebas de vulnerabilidades de Nessus pueden causar que los servicios o sistemas operativos se corrompan y caigan. El usuario puede evitar esto desactivando "unsafe test" (pruebas no seguras) antes de escanear. Actualmente existen dos versiones: "Home" y "Work" Esta última de pago y sin restricciones.” de Wikipedia (Indice)
  • 65. Esta herramienta de auditoria es la más valorada dentro de las auditorias de servicios webs, tiene una infinidad de plugins para auditar e intentar romper la seguridad de la web. Si nos fijamos en la imagen hay 3 advertencias en amarillo, que lo que vienen a decir es que el certificado autofirmado no es una vulnerabilidad como tal pero no se merece la confianza necesaria, y el otro es debido a la permisividad de compatibilidad con los usuarios con navegadores más antiguos. PHPSECINFO: Este programa nos sirve para auditar el php.ini y la configuración general de php de nuestro servidor. Es aplicación que muestra la información sobre la seguridad de un código PHP y nos sugiere ideas para mejorarlo. Ahora hay que dejar claro que no audita propiamente nuestro código sino que nos ayuda a configurar los cimientos donde se apoyara nuestro código. 11.- Comentarios sobre los clústeres Quería dedicar un apartado a los clústeres aunque finalmente no lo haya implementado, por las razones que veremos más adelante, ya que me parece de las tecnologías más importantes dentro de cualquier sistema informático que sea importante, ya que una buena clusterización nos permite tanto dar alta disponibilidad como mantener los datos a salvo en caso de falla de alguno de los sistemas. ¿Por qué no los he introducido al final? Pese a qué me parece una parte muy importante de un servicio que fuese grande, y debido ha que aunque hacer funcionar un clúster en Windows es fácil para ciertos servicios como puede ser el DFS de Windows que con apenas unos clics lo tienes funcionando no pasa lo mismo cuando quieres implementar una aplicación como MySQL, Apache2 o el servicio de PHP, y lo que más me molesto ya que yo en un principio quería un proyecto que manejase apache y mysql, pero decidí probar a (Indice)
  • 66. clusterizar IIS y MSSQL y el resultado fue el mismo, que llegado cierto punto de la clusterización de estos servicios especiales requieren una configuración de los registros de Windows en cada nodo, y tienen que ser ademas de todos los cambios generados por dichas aplicaciones ¿Por qué no Linux? Al principio no quería usar Linux por 2 motivos principales, la implementación de un clúster básico de Windows es muy sencilla, cosa que no se puede decir lo mismo de las distribuciones de Linux que he manejado y la segunda era que ya sabía hacer un clúster de Windows. Después de mucha investigación he concluido que cierto es que para ciertas operaciones como mantener un servidor DFS y otros servicios concretos de Windows puede resultar muy cómodo un clúster en Windows, pero para proyectos webs, es indiscutiblemente mejor y más fácil de implementar al final pese a que hay que usar de medía 3 programas distintos, y un mínimo de 3 equipos, al final una vez bien configurado un clúster de Linux realiza una muy buena labor ya que por un lado mantiene sincronizada toda la información como que además pueden funcionar como equipos en solitario, una opción que para ciertas situaciones puede ser muy importante. Pero el motivo por el que pese haberme documentado sobre estos clústeres llegue a la conclusión que si quería un clúster en Linux, que a su vez fuese seguro, no me daba tiempo material a realizarlo, ya que como muchas cosas en Linux pese a que se puede hacer todo hay que hacerlo sin ningún tipo de asistente ni script rápido por lo que para hacer un clúster que no sea funcional al 100% he decidido apartarlo del proyecto. 12.- Comentarios generales. En mi opinión personal este proyecto me ha ayudado a ver una serie de cosas como la clusterización en Linux o la importancia de usar $_POST en lugar de $_GET para el tratamiento de las peticiones sean seguras a la hora del desarrollo web, la infinidad de opciones que nos da php, y su facilidad de uso e implementación. También me ha generado inquietudes sobre la seguridad en la web y la facilidad que hay de generar vulnerabilidades en un servidor que este mal configurado, pese a que se que para terminar de fortificar este servidor habría que hacer una buena configuración de IPTables. El proyecto en general me ha gustado mucho al realizarlo debido a que en el fondo se que es la base de muchos juegos online, obviamente aun le faltaría mucho trabajo para poder llevarlo a un ambiente de producción pero se que son unos buenos cimientos sobre los que poder empezar a trabajar algo de un nivel más serio. (Indice)