Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Temas - ~ Yoya ~

#1
Zona Webmaster / Redis como Session Handler en PHP
Enero 17, 2015, 11:51:51 PM
Tengo mucho tiempo que no escribo algún articulo, así que es posible que no me quede tan bien :P.



En este articulo se configurara dos Apache Server para que guarden las sesiones de los cliente en un Servidor Redis. De esta forma ambos servidores pueden acceder a las sesiones de los cliente.

La configuración es la siguiente:

Tengo 2 nodos:

  • Nodo A IP: 192.168.0.3
  • Nodo B IP: 192.168.0.12
En el Nodo A, esta corriendo los siguientes servicios:

  • Nginx Server
  • Redis Server
  • Apache Server

Nodo B:

  • Apache Server

Nodo A corre sobre Fedora 21, Nodo B corre sobre Fedora 20.




  • Los clientes realizan petición contra el servidor de Nginx
  • El Servidor Nginx enruta las peticiones hacia el Servidor Apache en el Nodo A. En caso de que el Servidor Apache del Nodo A no este disponible, entonces Nginx enrutara las peticiones hacia el Servidor Apache del Nodo B
  • Las sesiones que se crearan en el Servidor de Redis, y cada vez que se necesite leer la data de una sesion se realizara contra el Servidor de Redis


Como funcionan las sesiones.


Es necesario instalar y configurar en ambos Apache Server la extensión PHP-Redis que permite la comunicación con un servidor Redis: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Ambos Apache Server están corriendo sobre el puerto 8080. Nginx estará corriendo sobre el puerto 80 en el Nodo A. Utilizare el servidor de Nginx como Load Balancer para los Apache Server configurados en los dos nodos. El Apache Server del Nodo A, sera configurado como primario, y recibirá todas las conexiones entrantes. El Apache Server del Nodo B, sera configurado como Failover, osea que cuando el Apache Server del Nodo A no responda, entonce Nginx enrutará todas las conexiones hacia el Apache Server del Nodo B.

Configuración de NGINX
Código: ini
upstream httpbackendserver {
    server 192.168.0.3:8080;
    server 192.168.0.12:8080 backup;

    }

    server {
        listen       80 default_server;
        server_name  localhost;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
            proxy_pass http://httpbackendserver;
        }

    Directivas importantes:
    • upstream: sirve para definir un grupo de server. La usaremos para definir nuestro HTTP Server.
    • server: sirve para definir un servidor y sus parámetros. En este caso definimos el servidor del nodo B, con el parámetro backup.

    Luego de instalar la extensión de Redis para PHP, de haber reiniciado el servidor Apache, entonces hay que configurar PHP para que almacenes las sesiones en el servidor de Redis. De esta forma cada vez que se vaya a utilizar sesiones, hay que utilizar Redis como repositorios de las sesiones. Para indicar que Redis maneje la sesiones guardada, hay que configurar las directivas
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta y No tienes permitido ver los links. Registrarse o Entrar a mi cuenta del php.ini, de esta forma:
Código: ini
session.save_handler = redis
session.save_path    = tcp://redis-host:redis-port


En mi caso lo hice un poco mas portable, modifico las directivas desde un archivo PHP (teniendo en cuenta que la modificación solo tendrá efecto siempre y cuando se ejecute el mismo archivo PHP).

Código: php-brief

<?php

ini_set('session.save_handler', 'redis');
ini_set('session.save_path',    'tcp://192.168.0.3:6379');

session_start();


echo "Server 1,  ";
if(!empty($_GET['set'])) {
    $_SESSION['data'] = $_GET['set'];
}

if(!empty($_GET['show']) && $_GET['show'] == 1) {
echo "Session data: ".$_SESSION['data'];
}


echo "Hola mundo";
?>


Tengo las siguientes URL:

  • 192.168.0.3/test.php?set=data_a_setear
  • 192.168.0.3/test.php?show=1
La primera URL se utiliza para setear información a la sesión data. La segunda URL se utiliza para ver la información que contiene la sesión data.




Bajo el servidor Apache del Nodo 1, para que Nginx enrute todas las peticiones hacia el servidor de Apache del nodo 2.



De esta forma se puede ver que Nginx ha enrutado todas las peticiones hacia el Servidor Apache en el Nodo B, y el Servidor Apache en el Nodo B utiliza la data de la sesiones creada en el Servidor Apache en el Nodo A.

Data de la sesion guardada en el Servidor de Redis:
Código: bash
[yoya@127 ~]$ redis-cli
127.0.0.1:6379> KEYS *
1) "PHPREDIS_SESSION:n30kep1lkgnks7knlkppps6c10"
127.0.0.1:6379> get "PHPREDIS_SESSION:n30kep1lkgnks7knlkppps6c10"
"data|s:9:\"Underc0de\";"
127.0.0.1:6379>




Este tipo de configuración se puede utilizar en ocasiones en la que es posible que no siempre el mismo servidor maneje la comunicación  con el mismo cliente. También en ocasiones en que se esta trabajando una mejora de la misma aplicación y se desea que los cliente no tengan ningún tiempo de inactividad en la transferencia de la aplicación vieja a la aplicación nueva.

También hay que tener en cuenta el acceso a la sesiones en Redis sera mas rápido que acceder a la información de la sesiones almacenadas en archivos en el sistema operativo, ya que la información en Redis reside en la memoria. Pero esta afirmación dependerá del contexto donde se encuentre los servidores.

Existe configuraciones similares para el manejo de sesiones como realizar un shared disk para almacenar los archivos de sesiones generados en los servidores.

Saludos!

URLs:
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
#2
Dado el codigo de abajo, explicar porque retorna true o false, en cada caso.

Código: java
public class xD {
    public static void main(String[] args) {

        Integer a1 = 600;
        Integer a2 = 600;

        Integer b1 = 100;
        Integer b2 = 100;

        String a = "hola";

        StringBuilder strB = new StringBuilder("hola");

        System.out.println(new Integer(5) == new Integer(5)); // false
        System.out.println(a1 == a2);// false
        System.out.println(b1 == b2); //true
        System.out.println(a.equals("hola")); //true
        System.out.println(strB.equals("hola")); // false

    }
}


Salida:

Citarfalse
false
true
true
false

Saludos.
#3
Bueno este tema era para dar respuesta a uno, pero pienso que es mejor crear un POST.

Este tema es simple de entender, y en este tema se aplica el concepto de abstraccion y aquí se puede ver la utilidad.

Bueno normalmente cuando se crea un sistema utilizando POO, siempre se piensa en crear una clase padre, esta clase padre es recomendable que sea abstracta, ya que la finalidad de esta clase es ser heredara y  implementar todos sus métodos abstractos.


Ahora aplicando ese concepto al ámbito de base de datos. Se tiene lo siguiente: En toda base de datos es necesario realizar una conexión, también se realiza sentencias SQL, se devuelve un resultado y se cierra la conexión. Eso es lo que tienen en común, MYSQL, PostgreSQL, etc... Todo lo que tienen en comun, en la clase padre, se debe declarar como metodos abstractos. Metodos porque realizan una accion y deben ser abstracto porque el procedimiento para la implementación es diferente, osea no utilizas la misma función para conectarte a un servidor MYSQl que para uno PostgreSQL.

Bueno, aqui el codigo, no lo he probado ni nada, es un Poc para que tengan una idea.

Código: php

abstract class BaseDeDatos {

abstract public function conectar($user, $pass, $db, $host);
abstract public function sql($sql);
abstract public function resultado();
abstract public function cerrarConexion();
}


MYSQL
Código: php

class Mysql extends BaseDeDatos {

public function  conectar($user, $pass, $db, $host) {

//Me conecto al servidor con el usuario y pass, y selecciono la base de datos, luego devuelvo el objeto para luego realizar consultas
//Codigo
//Codigo
//Codigo
}

public function sql($sql) {
//Codigo que realiza la consulta SQL, y guarda el resultado en una variable para su posterior uso
//Codigo
//Codigo
//Codigo
//Codigo
}

public function resultado() {
//Retorno el resultado de la consulta SQL
//Codigo
//Codigo
//Codigo
}

public function cerrarConexion(){
//Cierro la conexion que cree
//Code
//Code
//Code
}
}


PostgreSQL
Código: php

class PostgreSQL extends BaseDeDatos {

public function  conectar($user, $pass, $db, $host) {

//Me conecto al servidor con el usuario y pass, y selecciono la base de datos, luego devuelvo el objeto para luego realizar consultas
//Codigo
//Codigo
//Codigo
}

public function sql($sql) {
//Codigo que realiza la consulta SQL, y guarda el resultado en una variable para su posterior uso
//Codigo
//Codigo
//Codigo
//Codigo
}

public function resultado() {
//Retorno el resultado de la consulta SQL
//Codigo
//Codigo
//Codigo
}

public function cerrarConexion(){
//Cierro la conexion que cree
//Code
//Code
//Code
}
}


Espero que con eso se haya entendiendo el concepto. Y eso ya da cabida a poder implementar otros sistema de gestión de base de datos. Con eso se consigue tener algo mas generico, osea no importa con que base de datos estes trabajando, vas a utilizar todo de la misma manera.

Hay se aplica 5 muy importante puntos.

1 - Se crea un sistema escalable, osea que se puede implementar en un futuro otros sistema de base de datos, sin necesidad de agregar codigo ni modificar codigo de alguna clase ya existente.

2 - Se aplica el principio open-closed. Las clases deben estar abierta a extensiones, pero cerrada a modificaciones. Como lo ven, apartir de la clase BaseDeDatos, se crea una extencion para MySQL, PostgreSQL pero no hay necesidad de modificar la clase BaseDeDatos.

3 - Se aplica correctamente la herencia. No tienes permitido ver los links. Registrarse o Entrar a mi cuenta. Osea MySQL es una Base de datos, PostgreSQL es una base de datos. -- Mysql is a BaseDeDatos, PostgreSQL is a BaseDeDatos.

4 - Se aplica correctamente la abstraccion.

5 - Da cabida al polimorfismo

Saludos.
#4
La verdad no pensaba publicar esto, pero me pareció un poco interesante  y pensaba que a muchos les resultaría interesante igual. No hay problema si se publica en algún blog o foro, mientras se agregue la fuente.



Buscando un ejemplo de la estructura de los hash que genera joomla para agregarlo a la lista de hash que detecta la herramienta IHash. Opte por descargarme joomla y instalarlo (la versión 2.5.8 que es la que recomiendan) para verlo con mis propios ojos. Luego de instalarlo, cree un usuario directamente desde el panel de administración, llamado example con el password "example" para luego no olvidarme.

Ahora toca ver todas las tablas que contiene la base de datos donde instale joomla.
Código: mysql
mysql> use joomla;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-----------------------------+
| Tables_in_joomla            |
+-----------------------------+
| jom_assets                  |
| jom_associations            |
| jom_banner_clients          |
| jom_banner_tracks           |
| jom_banners                 |
| jom_categories              |
| jom_contact_details         |
| jom_content                 |
| jom_content_frontpage       |
| jom_content_rating          |
| jom_core_log_searches       |
| jom_extensions              |
| jom_finder_filters          |
| jom_finder_links            |
| jom_finder_links_terms0     |
| jom_finder_links_terms1     |
| jom_finder_links_terms2     |
| jom_finder_links_terms3     |
| jom_finder_links_terms4     |
| jom_finder_links_terms5     |
| jom_finder_links_terms6     |
| jom_finder_links_terms7     |
| jom_finder_links_terms8     |
| jom_finder_links_terms9     |
| jom_finder_links_termsa     |
| jom_finder_links_termsb     |
| jom_finder_links_termsc     |
| jom_finder_links_termsd     |
| jom_finder_links_termse     |
| jom_finder_links_termsf     |
| jom_finder_taxonomy         |
| jom_finder_taxonomy_map     |
| jom_finder_terms            |
| jom_finder_terms_common     |
| jom_finder_tokens           |
| jom_finder_tokens_aggregate |
| jom_finder_types            |
| jom_languages               |
| jom_menu                    |
| jom_menu_types              |
| jom_messages                |
| jom_messages_cfg            |
| jom_modules                 |
| jom_modules_menu            |
| jom_newsfeeds               |
| jom_overrider               |
| jom_redirect_links          |
| jom_schemas                 |
| jom_session                 |
| jom_template_styles         |
| jom_update_categories       |
| jom_update_sites            |
| jom_update_sites_extensions |
| jom_updates                 |
| jom_user_notes              |
| jom_user_profiles           |
| jom_user_usergroup_map      |
| jom_usergroups              |
| jom_users                   |
| jom_viewlevels              |
| jom_weblinks                |
+-----------------------------+
61 rows in set (0.00 sec)


Directamente me fije en la tabla jom_users. Supuse que hay es donde se guardan los datos que tienen que ver con el nombre de usuario y password. Ahora toca ver la estructura de la tabla jom_users para verificar los campos que tiene para realizar la próxima consulta SQL.

Código: mysql
mysql> describe jom_users;
+---------------+--------------+------+-----+---------------------+----------------+
| Field         | Type         | Null | Key | Default             | Extra          |
+---------------+--------------+------+-----+---------------------+----------------+
| id            | int(11)      | NO   | PRI | NULL                | auto_increment |
| name          | varchar(255) | NO   | MUL |                     |                |
| username      | varchar(150) | NO   | MUL |                     |                |
| email         | varchar(100) | NO   | MUL |                     |                |
| password      | varchar(100) | NO   |     |                     |                |
| usertype      | varchar(25)  | NO   | MUL |                     |                |
| block         | tinyint(4)   | NO   | MUL | 0                   |                |
| sendEmail     | tinyint(4)   | YES  |     | 0                   |                |
| registerDate  | datetime     | NO   |     | 0000-00-00 00:00:00 |                |
| lastvisitDate | datetime     | NO   |     | 0000-00-00 00:00:00 |                |
| activation    | varchar(100) | NO   |     |                     |                |
| params        | text         | NO   |     | NULL                |                |
| lastResetTime | datetime     | NO   |     | 0000-00-00 00:00:00 |                |
| resetCount    | int(11)      | NO   |     | 0                   |                |
+---------------+--------------+------+-----+---------------------+----------------+
14 rows in set (0.00 sec)


Directamente vi que los campos que me interesaban, era id, username (contiene el nombre de usuario para loguearse) y password (el campo mas importante, contiene el hash que genera joomla).

Código: mysql

mysql> select id, username, password from jom_users;
+----+----------+-------------------------------------------------------------------+
| id | username | password                                                          |
+----+----------+-------------------------------------------------------------------+
| 73 | admin    | 07ac4817e34b93ee42e88ea0f0705e9a:3uQaeUYsbQf2F7aeehj75gYiuHARWpdJ |
| 74 | example  | edbea885d26f0557e748605c5a5707cd:NXhARsuArVRSZcs4U0lSDrpCDs0Le1Ch |
+----+----------+-------------------------------------------------------------------+
2 rows in set (0.00 sec)


Hay muestra los 2 usuarios, el primero que se crea cuando se instala joomla y el segundo usuario que cree directamente desde el panel de administración.

Hasta hay todo bien, había hecho todo lo que necesitaba pero me dio un poco de curiosidad ver como joomla genera los hash y también me servia para asegurarme de todo. Lo primero que hice fue buscar en google, ya que no quería leer el código de joomla para poder entender como generaba los hash joomla, mejor ver algún post de alguien que ya lo había leído :P.

Me encontré con este hilo: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Pero vi que fue hace 2 años y no estaba seguro si  joomla utilizaba el mismo método, así que me puse a revisar el source.

Indagando un poco, el método que generaba los hash era bind() que pertenecía a la clase JUser del archivo user.php que se encontraba en el directorio libraries/joomla/user.

user.php - metodo bind
Código: php
public function bind(&$array)
{
// Let's check to see if the user is new or not
if (empty($this->id))
{
// Check the password and create the crypted password
if (empty($array['password']))
{
$array['password'] = JUserHelper::genRandomPassword();
$array['password2'] = $array['password'];
}

// TODO: Backend controller checks the password, frontend doesn't but should.
// Hence this code is required:
if (isset($array['password2']) && $array['password'] != $array['password2'])
{
$this->setError(JText::_('JLIB_USER_ERROR_PASSWORD_NOT_MATCH'));
return false;
}

$this->password_clear = JArrayHelper::getValue($array, 'password', '', 'string');

$salt = JUserHelper::genRandomPassword(32);
$crypt = JUserHelper::getCryptedPassword($array['password'], $salt);
$array['password'] = $crypt . ':' . $salt;

// Set the registration timestamp

$this->set('registerDate', JFactory::getDate()->toSql());

// Check that username is not greater than 150 characters
$username = $this->get('username');
if (strlen($username) > 150)
{
$username = substr($username, 0, 150);
$this->set('username', $username);
}

// Check that password is not greater than 100 characters
$password = $this->get('password');
if (strlen($password) > 100)
{
$password = substr($password, 0, 100);
$this->set('password', $password);
}
}
else
{
// Updating an existing user
if (!empty($array['password']))
{
if ($array['password'] != $array['password2'])
{
$this->setError(JText::_('JLIB_USER_ERROR_PASSWORD_NOT_MATCH'));
return false;
}

$this->password_clear = JArrayHelper::getValue($array, 'password', '', 'string');

$salt = JUserHelper::genRandomPassword(32);
$crypt = JUserHelper::getCryptedPassword($array['password'], $salt);
$array['password'] = $crypt . ':' . $salt;
}
else
{
$array['password'] = $this->password;
}
}

// TODO: this will be deprecated as of the ACL implementation
// $db = JFactory::getDbo();

if (array_key_exists('params', $array))
{
$params = '';

$this->_params->loadArray($array['params']);

if (is_array($array['params']))
{
$params = (string) $this->_params;
}
else
{
$params = $array['params'];
}

$this->params = $params;
}

// Bind the array
if (!$this->setProperties($array))
{
$this->setError(JText::_('JLIB_USER_ERROR_BIND_ARRAY'));
return false;
}

// Make sure its an integer
$this->id = (int) $this->id;

return true;
}


El método recibe como parámetro un array, pero si se fijan ponen al inicio el símbolo &. Eso indica que el array $array se pasa por referencia y por lo tanto los cambios que se hagan a la variable $array, dentro del metodo bind, afectara directamente al array que se le pase como parámetro al metodo bind(). El método bind retorna un booleano, si el usuario existe entonce retornaba un false, si era nuevo entonce un true (despues de haber generado el hash).

Nota: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta, ejemplo #2

Bueno aquí las 3 lineas que mas me interesa del metodo bind(), van desde linea 660 hasta la 662:
Código: php
				$salt = JUserHelper::genRandomPassword(32);
$crypt = JUserHelper::getCryptedPassword($array['password'], $salt);
$array['password'] = $crypt . ':' . $salt;


Al final el array guardaba el hash de esta forma crypt:salt
En la primera linea, llama el método estático genRandomPassword() de la clase abstracta JUserHelper que pertenece al archivo helper.php en el directorio libraries/joomla/user. Al método se le pasa como parámetro el numero 32.

Aquí las primeras 3 lineas del método genRandomPassword(), que basta con las 3 primera mas el nombre de la función para darse cuenta cual es el propósito.
Código: php
public static function genRandomPassword($length = 8)
{
$salt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";


El metodo retorna por defecto 8 caracteres al azar (a-z-A-Z0-9). Pero como se le pasa un 32 como parámetro, retornara 32 caracteres al alzar.

Eso quiere decir que la variable $salt contendrá 32 caracteres al azar. Ahora vamos a la segunda linea:

Código: php
				$salt = JUserHelper::genRandomPassword(32);
$crypt = JUserHelper::getCryptedPassword($array['password'], $salt);
$array['password'] = $crypt . ':' . $salt;


La variable $crypt almacena el valoro del resultado del método getCryptedPassword de la clase abstracta JUserHelper; se les pasa 2 parámetros al método getCryptedPassword que es el password (en texto plano) y los 32 caracteres generados de forma aleatoria. Aquí el método getCryptedPassword:

Código: php
public static function getCryptedPassword($plaintext, $salt = '', $encryption = 'md5-hex', $show_encrypt = false)
{
// Get the salt to use.
$salt = JUserHelper::getSalt($encryption, $salt, $plaintext);

// Encrypt the password.
switch ($encryption)
{
case 'plain':
return $plaintext;

case 'sha':
$encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext));
return ($show_encrypt) ? '{SHA}' . $encrypted : $encrypted;

case 'crypt':
case 'crypt-des':
case 'crypt-md5':
case 'crypt-blowfish':
return ($show_encrypt ? '{crypt}' : '') . crypt($plaintext, $salt);

case 'md5-base64':
$encrypted = base64_encode(mhash(MHASH_MD5, $plaintext));
return ($show_encrypt) ? '{MD5}' . $encrypted : $encrypted;

case 'ssha':
$encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext . $salt) . $salt);
return ($show_encrypt) ? '{SSHA}' . $encrypted : $encrypted;

case 'smd5':
$encrypted = base64_encode(mhash(MHASH_MD5, $plaintext . $salt) . $salt);
return ($show_encrypt) ? '{SMD5}' . $encrypted : $encrypted;

case 'aprmd5':
$length = strlen($plaintext);
$context = $plaintext . '$apr1$' . $salt;
$binary = JUserHelper::_bin(md5($plaintext . $salt . $plaintext));

for ($i = $length; $i > 0; $i -= 16)
{
$context .= substr($binary, 0, ($i > 16 ? 16 : $i));
}
for ($i = $length; $i > 0; $i >>= 1)
{
$context .= ($i & 1) ? chr(0) : $plaintext[0];
}

$binary = JUserHelper::_bin(md5($context));

for ($i = 0; $i < 1000; $i++)
{
$new = ($i & 1) ? $plaintext : substr($binary, 0, 16);
if ($i % 3)
{
$new .= $salt;
}
if ($i % 7)
{
$new .= $plaintext;
}
$new .= ($i & 1) ? substr($binary, 0, 16) : $plaintext;
$binary = JUserHelper::_bin(md5($new));
}

$p = array();
for ($i = 0; $i < 5; $i++)
{
$k = $i + 6;
$j = $i + 12;
if ($j == 16)
{
$j = 5;
}
$p[] = JUserHelper::_toAPRMD5((ord($binary[$i]) << 16) | (ord($binary[$k]) << 8) | (ord($binary[$j])), 5);
}

return '$apr1$' . $salt . '$' . implode('', $p) . JUserHelper::_toAPRMD5(ord($binary[11]), 3);

case 'md5-hex':
default:
$encrypted = ($salt) ? md5($plaintext . $salt) : md5($plaintext);
return ($show_encrypt) ? '{MD5}' . $encrypted : $encrypted;
}
}


Observando los parametros:
Código: php
getCryptedPassword($plaintext, $salt = '', $encryption = 'md5-hex', $show_encrypt = false)


el primer parámetro, corresponde al password (en texto plano), el salt que por defecto esta vació pero recordar que se envían 32 caracteres aleatorio, por lo tanto en este caso la variable $salt contendrá los 32 caracteres aleatorios. El tercer parámetro por defecto contiene el valor de md5-hex y el cuarto un booleano establecido como false.

Una linea importante es esta (la cuarta linea):

Código: php
$salt = JUserHelper::getSalt($encryption, $salt, $plaintext);


Ya que le esta dando un nuevo valor a la variable $salt. Aquí el método getSalt():

Código: php
public static function getSalt($encryption = 'md5-hex', $seed = '', $plaintext = '')
{
// Encrypt the password.
switch ($encryption)
{
case 'crypt':
case 'crypt-des':
if ($seed)
{
return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 2);
}
else
{
return substr(md5(mt_rand()), 0, 2);
}
break;

case 'crypt-md5':
if ($seed)
{
return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 12);
}
else
{
return '$1$' . substr(md5(mt_rand()), 0, 8) . '$';
}
break;

case 'crypt-blowfish':
if ($seed)
{
return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 16);
}
else
{
return '$2$' . substr(md5(mt_rand()), 0, 12) . '$';
}
break;

case 'ssha':
if ($seed)
{
return substr(preg_replace('|^{SSHA}|', '', $seed), -20);
}
else
{
return mhash_keygen_s2k(MHASH_SHA1, $plaintext, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
}
break;

case 'smd5':
if ($seed)
{
return substr(preg_replace('|^{SMD5}|', '', $seed), -16);
}
else
{
return mhash_keygen_s2k(MHASH_MD5, $plaintext, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
}
break;

case 'aprmd5': /* 64 characters that are valid for APRMD5 passwords. */
$APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

if ($seed)
{
return substr(preg_replace('/^\$apr1\$(.{8}).*/', '\\1', $seed), 0, 8);
}
else
{
$salt = '';
for ($i = 0; $i < 8; $i++)
{
$salt .= $APRMD5{rand(0, 63)};
}
return $salt;
}
break;

default:
$salt = '';
if ($seed)
{
$salt = $seed;
}
return $salt;
break;
}
}


Al parámetro getSalt() se le pasa como parámetro la variable $encryption que por defecto contiene el valor de md5-hex. De ese primer parámetro depende el comportamiento del método getSalt(). Ya que en el método getSalt() utiliza un switch y dependiendo del valor que contenga $encryption se comportara de forma diferente. Por defecto como $encryption contiene md5-hex, se ejecutara el default: del swtich. Que simplemente retorna el salt sin ningún tipo de cambio.

Por lo tanto en la linea:
Código: php
$salt = JUserHelper::getSalt($encryption, $salt, $plaintext);


La variable $salt contendrá el mismo valor que antes.

Bueno volviendo al metodo getCryptedPassword(), vemos que luego sigue un switch que evalúa la variable $encryption que dependiendo de esta se puede comportar de manera diferente. Recordando que la variable $encryption por defecto contiene el valor de md5-hex entonce vamos directamente a ese case

Código: php
			case 'md5-hex':
default:
$encrypted = ($salt) ? md5($plaintext . $salt) : md5($plaintext);
return ($show_encrypt) ? '{MD5}' . $encrypted : $encrypted;


Vemos que se utiliza el operador ternario para darle un nuevo valor a la variable $encrypted. Bueno si la variable salt contiene algún valor, entonce la variable $encrypted contendrá el valor del password+salt (32 caracteres alertorios) cifrado a MD5, sino la variable encrypted tendrá el valor del password cifrado en MD5. Luego, en la linea siguiente hay se retorna la variable $encrypted pero se utiliza el operador ternario para indicar 2 posibles casos. Si la variable $show_encrypt  es verdadera, entonce retorna $encrypted pero le agrega al inicio la cadena {MD5} sino retorna simplemente el valor de $encrypted.

Recordar que en el método getCryptedPassword() la variable $show_encrypt por defecto es false, por lo tanto en este caso retornara simplemente el valor de $encrypted.

Ahora vamos a la ultima linea:
Código: php
				$salt = JUserHelper::genRandomPassword(32);
$crypt = JUserHelper::getCryptedPassword($array['password'], $salt);
$array['password'] = $crypt . ':' . $salt;


Que simplemente contiene el valor de la variable $crypt el signo de : y luego el salt. Que es la estructura en que joomla guarda los hash que genera.

Código: php
mysql> select id, username, password from jom_users;
+----+----------+-------------------------------------------------------------------+
| id | username | password                                                          |
+----+----------+-------------------------------------------------------------------+
| 73 | admin    | 07ac4817e34b93ee42e88ea0f0705e9a:3uQaeUYsbQf2F7aeehj75gYiuHARWpdJ |
| 74 | example  | edbea885d26f0557e748605c5a5707cd:NXhARsuArVRSZcs4U0lSDrpCDs0Le1Ch |
+----+----------+-------------------------------------------------------------------+
2 rows in set (0.00 sec)


Ahora por lo tanto, es simple hacer un pequeño PoC (prueba de concepto).

Código: php
<?php

//PoC by Yoyahack

$hash = 'edbea885d26f0557e748605c5a5707cd:NXhARsuArVRSZcs4U0lSDrpCDs0Le1Ch';
$password = "example";

$estructura = explode(':', $hash);

$salt = $estructura[1];

echo "[+]Hash                    -> ".$hash."\n\n";
echo "Salt                    -> ".$salt."\n";
echo "password encriptado     -> ".$estructura[0]."\n";
echo "[*]md5(password+salt)   -> ".md5($password.$salt)."\n";

?>


Código: bash
yoya@OpenSUSE:~/www/public$ php a.php
[+]Hash                    -> edbea885d26f0557e748605c5a5707cd:NXhARsuArVRSZcs4U0lSDrpCDs0Le1Ch

Salt                    -> NXhARsuArVRSZcs4U0lSDrpCDs0Le1Ch
password encryptado     -> edbea885d26f0557e748605c5a5707cd
[*]md5(password+salt)   -> edbea885d26f0557e748605c5a5707cd
yoya@OpenSUSE:~/www/public$


Saludos.
#5
Zona Webmaster / Javascript Frameworks
Junio 21, 2011, 06:20:38 PM
Aqui un lista de los Javascript frameworks mas usados.

Jquery
Cita de: wikipedia
jQuery es una biblioteca o framework de JavaScript, creada inicialmente por John Resig, que permite simplificar la manera de interactuar con los documentos HTML, manipular el árbol DOM, manejar eventos, desarrollar animaciones y agregar interacción con la técnica AJAX a páginas web. Fue presentada el 14 de enero de 2006 en el BarCamp NYC.


  • Selección de elementos DOM.
  • Interactividad y modificaciones del árbol DOM, incluyendo soporte para CSS 1-3 y un plugin básico de XPath.
    Eventos.
  • Manipulación de la hoja de estilos CSS.
  • Efectos y animaciones.
  • Animaciones personalizadas.
  • AJAX.
  • Soporta extensiones.
  • Utilidades varias como obtener información del navegador, operar con objetos y vectores, funciones como trim() (elimina los espacios en blanco del principio y final de una cadena de caracteres), etc.
  • Compatible con los navegadores Mozilla Firefox 2.0+, Internet Explorer 6+, Safari 3+, Opera 10.6+ y Google Chrome 8+.4


Prototype
Cita de: wikipediaPrototype es un framework escrito en JavaScript que se orienta al desarrollo sencillo y dinámico de aplicaciones web. Es una herramienta que implementa las técnicas AJAX y su potencial es aprovechado al máximo cuando se desarrolla con Ruby On Rails.

Con la Web 2.0 las técnicas de desarrollo de páginas web necesitaban dar un gran salto. Con esto en mente nació la técnica AJAX, que gracias a Prototype permite el desarrollo ágil y sencillo de páginas Web, esto en relación al desarrollador, y provee al cliente una manera más rápida de acceder al servicio que solicita. Prototype es un Framework basado en JavasScript orientado a proporcionar al desarrollador de técnicas AJAX listas para ser usadas. El potencial de Prototype es aprovechado al máximo si se desarrolla con Ruby On Rails, esto no quiere decir que no se puede usar desde otro lenguaje, solamente que demandara un "mayor esfuerzo" en el desarrollo.



Mootools
Cita de: wikipediaMooTools (My oriented object tools) es un Framework web orientado a objetos para JavaScript, de código abierto, compacto y modular. El objetivo de MooTools es aportar una manera de desarrollar JavaScript sin importar en qué navegador se ejecute de una manera elegante. MooTools aporta una API documentada más enfocada a la orientación de objetos que la implementación estándar soportada por los navegadores web.

Ventajas
Como otras tantas bibliotecas JavaScript, MooTools aporta al usuario muchas ventajas. Alguna de ellas:

  • Es un Framework modular y extendible, el desarrollador puede elegir (específicamente) que componentes usar y cuales no.
  • MooTools es orientado a objetos y sigue los principios DRY, que hacen de él un Framework rico, potente y eficiente.
  • Componente avanzado de efectos (Effects), con transiciones (Transitions), de función parabólica, optimizadas y utilizadas por multitud de desarrolladores Flash.
  • Framework desarrollado por programadores para programadores.



Dojo

CitarDojo es un framework que contiene APIs y widgets (controles) para facilitar el desarrollo de aplicaciones Web que utilicen tecnología AJAX. Contiene un sistema de empaquetado inteligente, los efectos de UI, drag and drop APIs, widget APIs, abstracción de eventos, almacenamiento de APIs en el cliente, e interacción de APIs con AJAX.
Resuelve asuntos de usabilidad comunes como pueden ser la navegación y detección del navegador, soportar cambios de URL en la barra de URLs para luego regresar a ellas (bookmarking), y la habilidad de degradar cuando AJAX/JavaScript no es completamente soportado en el cliente. Es conocido como "la navaja suiza del ejército de las bibliotecas Javascript". Proporciona una gama más amplia de opciones en una sola biblioteca JavaScript y es compatible con navegadores antiguos.

Complementos

Los complementos de Dojo son componentes preempaquetados de código JavaScript, HTML y CSS que pueden ser usados para enriquecer aplicaciones web.

  • Menús, pestañas y tooltips.
  • Tablas ordenables, gráficos dinámicos y dibujado de vectores 2D.
  • Efectos de animación y la posibilidad de crear animaciones personalizables.
  • Soporte para arrastrar y soltar.
  • Formularios y rutinas de validación para los parámetros.
  • Calendario, selector de tiempo y reloj.
  • Editor online de texto enriquecido.
  • Núcleo de componentes (dijit) accesible desde versiones anteriores y lector de pantalla.



Yui(Yahoo User Interface)
CitarYahoo User Interface(YUI), una serie de bibliotecas escritas en JavaScript, para la construcción de aplicaciones interactivas (RIA). Liberadas bajo licencia BSD por parte de la compañía Yahoo. Dichas bibliotecas son utilizadas para el desarrollo web específicamente para ser usadas como la programación de aplicaciones de escritorio, con componentes vistosos y personalizables y con una amplia implementación con AJAX.