Iloo

https://iloo.wordpress.com

CentOS: llamadas sobre SSL

Se tienen los certificados:

  • ssl.key (privada)
  • ssl.cert (publica)
  • ca.cert
  • pass phrase

La llave publica ssl.cert, esta instalada en el servidor DEVIL.

Se necesita enviar un json mediante POST desde el servidor HOST (Centos7) a DEVIL (SAP) sobre SSL, esto implica enviar las llaves publica, privada a demás de tener una validación del certificado CA y el pass phrase.

Si se envía los datos por curl de esta manera:

curl -v --cert ./ssl.cert --key ./ssl.key --cacert ./ca.cert --header "Content-Type: application/json" --data '{"key":"value"}' https://devil.com/

Obtendríamos una respuesta como esta:

About to connect() to devil.com port 443 (#0)
Trying 123.123.123.123…
Connected to devil.com (123.123.123.123) port 443 (#0)
Initializing NSS with certpath: sql:/etc/pki/nssdb
CAfile: ca.cert
CApath: none
Server certificate:
subject: CN=…………………………………..
start date: Jan 22 00:00:00 2020 GMT
expire date: Jan 22 12:00:00 2022 GMT
common name: *…………………………………
issuer: CN=……………………………………
NSS error -8172 (SEC_ERROR_UNTRUSTED_ISSUER)
Peer's certificate issuer has been marked as not trusted by the user.
Closing connection 0
curl: (60) Peer's certificate issuer has been marked as not trusted by the user.
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.

Haciendo la misma llamada de manera insegura, agregando la opción -k:

curl -v -k --cert ./ssl.cert --key ./ssl.key --cacert ./ca.cert --header "Content-Type: application/json" --data '{"key":"value"}' https://devil.com/

La respuesta seria algo así:

About to connect() to devil.com port 443 (#0)
Trying 123.123.123.123…
Connected to devil (123.123.123.123) port 443 (#0)
Initializing NSS with certpath: sql:/etc/pki/nssdb
skipping SSL peer certificate verification
NSS: client certificate from file
subject: CN=…………………………………………………..
start date: May 22 00:00:00 2020 GMT
expire date: Feb 10 12:00:00 2021 GMT
common name: ………………………………………………….
issuer: CN=…………………………………………………
SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Server certificate:
subject: CN=*………………………………………………….
start date: Jan 22 00:00:00 2020 GMT
expire date: Jan 22 12:00:00 2022 GMT
common name: *…………………………………………………
issuer: CN=……………………………………………………
POST /http/Orders HTTP/1.1
User-Agent: curl/7.29.0
Host: devil.com
Accept: /
Content-Type: application/json
Content-Length: 664
upload completely sent off: 664 out of 664 bytes
< HTTP/1.1 401
< X-message-code: PWD_WRONG
< WWW-Authenticate: Basic realm="SAP HANA Cloud Platform"
< Transfer-Encoding: chunked
< Date: Thu, 28 May 2020 19:32:54 GMT
< Server: SAP
< Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
<
Connection #0 to host devil.com left intact

Un detalle si se usa la opción -k los parámetros cacert y capath dejan de funcionar

Bien la solución es instalar(copiar) el certificado ca.cert, de la siguiente manera:

cp ca.cert /etc/pki/ca-trust/source/anchors/
update-ca-trust extract

Con esto la llamada de forma segura (sin el parámetro -k ) y sin el certificado CA debería ser exitosa.

curl -v --cert ./ssl.cert --key ./ssl.key --header "Content-Type: application/json" --data '{"key":"value"}' https://devil.com/

Este problema también afecta a las llamadas curl que se hacen desde PHP

wget: enviar peticiones POST sobre SSL

Se necesita enviar datos json mediante POST sobre SSL. Se tienen los certificados:

  • ssl.key
  • ssl.cert
  • cacert.cert

El código para el envío del json por POST:

wget -O- --post-data='{"key":"value"}' --header='Content-Type:application/json' --certificate=ssl.cert --private-key=ssl.key --ca-certificate=cacert.cert -nv 'https://www.host.com'

openssl: remover passphrase

Se tienen las keys generadas usando un passphrase:

  • ssl.key
  • ssl.cert
  • ca.cert

Al parecer hay un problema usando curl (lo dejare para otra ocasión) en Centos7, parece estar relacionado a NSS, la petición con curl seria:

--
curl -v -k --cert ./ssl.cert --key ./ssl.key --cacert ./ca.cert  --pass 'passphrase' --header "Content-Type: application/json" --data '{"key":"value"}' https://host.com
--

Esta petición no funciona correctamente incluso de forma insegura, agregando la opción -k, por lo que se intenta usar el comando wget para enviar la petición, el problema es que por medio de wget no existe la opción de envío del passphrase, por tanto el paso seria remover este passphrase, lo cual se hace de la siguiente manera:

--
openssl rsa -in ssl.key -out new_ssl.key
--

Ruby on Rails: puma en producción con SSL

Los detalles:

Servidor de producción: Centos 7

Servidor web: Apache 2.4.6

Ruby: 2.4.2

Esta guía es un compendio de varias guías que se pueden encontrar en internet.

Assets

Este archivo es importante para poder cargar los assets.

#/etc/httpd/conf.d/puma.conf

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RequestHeader unset X-Forwarded-Proto
<locationmatch "^/assets/.*$">
	Header unset ETag
	FileETag None
	ExpiresActive On
	ExpiresDefault "access plus 1 year"
</locationmatch>

<locationmatch "^/assets/.*\.(css|js)$">
	RewriteEngine on
	RewriteCond %{HTTP:Accept-Encoding} \b(x-)?gzip\b
	RewriteCond %{REQUEST_FILENAME}.gz -s
	RewriteRule ^(.+)$ $1.gz
</locationmatch>

<locationmatch "^/assets/.*\.css\.gz$">
	ForceType text/css
	Header set Content-Encoding gzip
	Header add Vary Accept-Encoding
</locationmatch>

<locationmatch "^/assets/.*\.js\.gz$">
	ForceType application/javascript
	Header set Content-Encoding gzip
	Header add Vary Accept-Encoding
</locationmatch>

AddOutputFilterByType DEFLATE text/html

Apache

Configuramos el archivo /etc/httpd/conf/httpd.conf:

<VirtualHost 111.222.333.444:80>
ServerName puma.web.com
DocumentRoot /home/puma/public_html/puma/public

include /etc/httpd/conf.d/puma.conf
Redirect permanent / https://puma.web.com/

<Directory /home/puma/public_html/puma/public>
AllowOverride All Options=FollowSymLinks,MultiViews
Order deny,allow
Allow from all
</Directory>
</VirtualHost>


<VirtualHost 111.222.333.444:443>
ServerName puma.web.com
DocumentRoot /home/puma/public_html/puma/public

include /etc/httpd/conf.d/puma.conf
RewriteRule ^/(.*)$ https://0.0.0.0:9294%{REQUEST_URI} [P]

<Directory /home/puma/public_html/puma/public>
AllowOverride All Options=FollowSymLinks,MultiViews
Order deny,allow
Allow from all
</Directory>

SSLProxyEngine On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off

SSLEngine on
SSLCertificateFile /home/puma/public_html/puma/FILE.cert
SSLCertificateKeyFile /home/puma/public_html/puma/FILE.key
SSLProtocol +TLSv1.2
SSLCACertificateFile /home/puma/public_html/puma/FILE.crt
</VirtualHost>

Puma

Se tiene que iniciar usando dos puertos uno para http y el otro para https, de la siguiente manera:

puma -d -b "ssl://127.0.0.1:9294?key=FILE.key&cert=FILE.cert&verify_mode=none&ca=FILE.crt" -b "tcp://127.0.0.1:9293" -e production

Cambiando los nombres de los archivo FILE.* por los de su certificado

Los puertos pueden ser cualquiera que no estén siendo usandos, podrían ser el 3000 y 3001 no hay problema.

 

 

 

 

Android: fallan las conexiones

Vamos indicando el entorno, se tiene una app en Android y que hace llamadas de tipo POST a un servidor para obtener datos, el servidor cuenta con SO Centos 6, apache, php 5.6, mysql, un servidor normal.

Lo que sucede, se tiene varios dispositivos de la misma red (6 dispositivos) trabajando con la app al mismo tiempo, cuando ingresa uno nuevo suceden dos cosas.

  • El ultimo simplemente deja de recibir la informacion del servidor por medio de la app.
  • Todas se bloquean excepto el primer dispositivo que uso la app.

Los mensajes de error en adroid son los siguientes:

org.apache.http.conn.HttpHostConnectException: Connection to https://xxx.com/ refused
java.net.SocketTimeoutException: failed to connect to xxx.com/111.222.333.444 (port 443) after 3000ms

La solucion en este caso fue desactivar el TCP timestamps de centos.

echo "0" > /proc/sys/net/ipv4/tcp_timestamps