Senha vísível no código fonte

Olá, colegas.

Estou criando um formulário que armazena as informações em bancos de dados, nada extraordinário… E ao colocar a senha no getConnection, no DriverManager, fui perspicaz ao observar que a senha que digitei podia ser lida.
E eu conheço um aplicativo que decodifica .class para .java (http://java.decompiler.free.fr/?q=jdgui)… Logo, se um usuário tiver acesso ao .class, pode ter acesso ao .java e descobrir a senha do banco de dados, assim, acessá-lo. Isso seria um problema de segurança. Estou certo? Alguém sabe como resolver? Como está sendo feito?

Agradeço desde já.
Lucas Ribeiro

Você poderia usar um ofuscador de código. Desse modo ficaria muito, mas muito dificil mesmo de descobrir a senha usando um descompilador. [=

Joinha cara, usa criptografia MD5, até onde sei não pode ser descriptografada, ou pelo menos e muito difícil.

Aqui no fórum mesmo existem vários tópicos sobre isto.
Abraço

http://www.guj.com.br/java/282554-criptografia-md5-

O servidor de aplicação deve ser um lugar seguro, onde poucos usuários tem acesso. Se alguém consegue invadir o servidor de aplicação e tirar os .class de lá, essa sua preocupação vai ser o menor dos problemas.

Só que o problema dele é uma senha de banco de dados, que não tem nada a ver com MD5.

No caso do Oracle, pode-se usar um troço chamado Oracle Wallet:

http://docs.oracle.com/cd/B10501_01/network.920/a96573/asologin.htm#1004574

Não sei como usar isso, mas o básico é que você cria um arquivo e o põe junto com a sua aplicação. Isso é feito de maneira que você não precisa se preocupar se o arquivo for copiado para outra máquina.

Assim como o ViniGodoy disse,
geralemente se deixa configurado no servidor de aplicações, pelo menos em todos os projetos que participei eram assim.

Isso aí, o padrão é usar datasources, um recurso em que o servidor é responsável por gerenciar as conexões com banco de dados e manter a senha guardada de forma segura. A aplicação nem fica sabendo a senha.

Procure no google sobre como fazer a configuração, de acordo com o servidor que estiver utilizando. É só pesquisar “datasource tomcat”, “datasource jboss”, etc…

EDIT:
Agora percebi que não tenho certeza se o sistema envolve um servidor de aplicação, ou se é 100% desktop

[quote=wellington.nogueira][quote=Hebert Coelho]Você poderia usar um ofuscador de código. Desse modo ficaria muito, mas muito dificil mesmo de descobrir a senha usando um descompilador. [=[/quote]Esqueci, Ofuscador + senhas = possível exceção adicionada ao ofuscamento.[/quote]Bom saber. [= Nuca precisei usar até hoje, valeu pela dica. [=

Seguinte pelo visto a dica dado pelo vini funciona bem para servidores de aplicações. Aqui para o meu caso tenho aplicações também em Desktop/Swing e uso JPA para conexão com o banco de dados e configuro meu usuário e senha no arquivo “persistence.xml” ao descompactar o .jar vejo que esse arquivo e acessado facilmente(nem precisa de programa adicional), qual seria a melhor solução para meu caso? Consigo mandar a senha dinamicamente do meu código java para configurar a conexão com meu banco através de JPA?

No caso de aplicações desktop acho que a dica do lpbianco já resolve bem. Basta colocar a senha num arquivo separado e criptografá-lo usando md5 ou sha-1 por exemplo. Quando iniciar a app, é só ler o arquivo e configurar a senha do banco programaticamente.

Olhei aqui é encontrei uma solução, para meu caso onde eu retiro os dados de conexão do persistencia.xml e passo através de parametros do programa em java, assim fica mais fácil já que posso usar um ofuscador de código ou alguma criptografia para os dados do banco. Já testei e alterei segue link de pesquisa abaixo:

http://stackoverflow.com/questions/13140082/change-content-in-persistence-xml-dynamically-during-execution

Agora e fazer alterar para todos os projetos que use os mesmos modelos.

A solução como um todo pode ser uma boa idéia, mas tem um erro no que vcs falaram:

MD5 e SHA não são algoritmos de criptografia e sim de Digest (hash), por isso não dá para ler de volta - como o próprio lpbianco disse, realmente não tem como trazer o dado original de volta. Nunca mais.

Se quiser usar essa solução use criptografia/decriptografia e não digest. Por exemplo o algoritmo AES.

A solução como um todo pode ser uma boa idéia, mas tem um erro no que vcs falaram:

MD5 e SHA não são algoritmos de criptografia e sim de Digest (hash), por isso não dá para ler de volta - como o próprio lpbianco disse, realmente não tem como trazer o dado original de volta. Nunca mais.

Se quiser usar essa solução use criptografia/decriptografia e não digest. Por exemplo o algoritmo AES.[/quote]

Bem lembrado. Eu normalmente uso estes algoritmos pra criptografar a senha do usuário e jogar no banco. Mas certamente não tenho como descriptografar…

A solução como um todo pode ser uma boa idéia, mas tem um erro no que vcs falaram:

MD5 e SHA não são algoritmos de criptografia e sim de Digest (hash), por isso não dá para ler de volta - como o próprio lpbianco disse, realmente não tem como trazer o dado original de volta. Nunca mais.

Se quiser usar essa solução use criptografia/decriptografia e não digest. Por exemplo o algoritmo AES.[/quote]

gomesrod também pensei o mesmo, porque sei que md5 não é possível descriptografar(ou pelo menos ainda não descobriram como faze-lo), eu geralmente uso um algoritmo de Vigenere para criptografar, já que fiz uma implementação em cima dele, porém alterei ele para abranger mais caracteres.

Isso dificulta ligeiramente as coisas! :slight_smile:

Aqui tem uma aplicação que usa essa solução de guardar a senha criptografada em arquivo, mas é só para não ficar totalmente visível para alguém que esteja passeando pelos diretórios.

Quando se considera a possibilidade de um atacante realmente determinado a obter a senha, e de quebra com acesso ao ambiente de execução e ao código-fonte (no caso via descompilação), fica praticamente impossível.

Uma das opções mais seguras que vi aqui no tópico foi colocar o segredo em um programa nativo. Mesmo assim, tendo acesso ao programa Java é possível deduzir como esse programa nativo é chamado e criar uma outra aplicação só para chamar as funções e mostrar o resultado.

Enfim, só o que se pode fazer é dificultar mesmo…

[quote=gomesrod]

Uma das opções mais seguras que vi aqui no tópico foi colocar o segredo em um programa nativo…[/quote]

Será?

Experimente fazer o seguinte: compile o seguinte programa em C:

#include <stdio.h>
main () {
    printf ("2beIWc5RAZj28D4kiK0c1WCtEeRvkb03il6t+ANP474tTZC4");
}

Agora, usando o programa “strings” (é um programa que varre qualquer arquivo binário ou texto e separa as strings) você vai ter a seguinte saída (compilei o programa acima com as opções padrão do VS 2010) . Reparem na linha 566.


Strings v2.4
Copyright (C) 1999-2007 Mark Russinovich
Sysinternals - www.sysinternals.com

(null)
mscoree.dll
runtime error 
TLOSS error
SING error
DOMAIN error
R6033
- Attempt to use MSIL code from this assembly during native code initialization
This indicates a bug in your application. It is most likely the result of calling an MSIL-compiled (/clr) function from a native constructor or from DllMain.
R6032
- not enough space for locale information
R6031
- Attempt to initialize the CRT more than once.
This indicates a bug in your application.
R6030
- CRT not initialized
R6028
- unable to initialize heap
R6027
- not enough space for lowio initialization
R6026
- not enough space for stdio initialization
R6025
- pure virtual function call
R6024
- not enough space for _onexit/atexit table
R6019
- unable to open console device
R6018
- unexpected heap error
R6017
- unexpected multithread lock error
R6016
- not enough space for thread data
R6010
- abort() has been called
R6009
- not enough space for environment
R6008
- not enough space for arguments
R6002
- floating point support not loaded
@Microsoft Visual C++ Runtime Library
...
<program name unknown>
Runtime Error!
Program: 
KERNEL32.DLL
HH:mm:ss
dddd, MMMM dd, yyyy
MM/dd/yy
December
November
October
September
August
July
June
April
March
February
January
Dec
Nov
Oct
Sep
Aug
Jul
Jun
May
Apr
Mar
Feb
Jan
Saturday
Friday
Thursday
Wednesday
Tuesday
Monday
Sunday
Sat
Fri
Thu
Wed
Tue
Mon
Sun
WUSER32.DLL
         (((((                  H
         h((((                  H
                                 H
CONOUT$
!This program cannot be run in DOS mode.
3mLfw
"5w
"5w
"5~t
"5w
#5=
"5Richw
~#Q
.text
`.rdata
@.data
.reloc
j [
 Pj
YY]
VVj
u`3
uNSW
u S
_@[
t'V
Y^]
Hpu
Hpu
QSV
8*u
@u^V
<Xw
 tJ
t%HHt
*u,
*u&
ItU
htD
?lu
<6u
<3u
Yt"
HHtXHHt
HHty+
itq
nt(
guc
?-u
RPSW
90tW
?If90t
@t2
Yt(
_^3
PPPPP
0^]
hP$@
SVW
Y__^[
350
_^[
9csm
t h
8csm
uTVWh
_^t
j h0
VSf
PPPPP
<v*V
^SSSSS
tA3
_^3
j$Y
~d=
vdj
^`[
_^]
<=t
>=Y
t"j
t?VSP
Y[_^
PPPPP
>"u
< t
>\t
>"u&
8"u
< tK<
VW9
PSS
?sJ
r6P
_^[
wf93t
f90u
f90u
VVV+
@PSVV
t8P
t*VV
SVV
_^[
j@j ^V
YY3
SWf9M
j@j 
t>W
t3%
_[^
uNh
t:V
F\=
t#W
Y;=
Whp
tDh
t0V
^_[
VW3
u'9
_^]
VW3
u'9
_^]
VW3
u,9E
t'9
_^]
~,WPV
98t^
tVPV
YY3
t/9U
VW3
@_^
u+h
@Ou
@Nu
j R
WPW
WPW
Gpt
@Iu
_^3
Fh=
^hS
_^[]
to=H
t^9
tD9
Y9_
Y_^[]
t4V
t(W
Fpt"
SSQ
_[^
VW3
v6;
WSV
_^[
t&;
j"^
QSWVj
WSV
YY]
;T$
;D$
N+D$
+D$
ti3
SVW
URPQQh M@
D$0
L$,3
T$4
_^[
UVWS
[_^]
SVWj
_^[]
8PE
f9H
_^[]
hP$@
SVW
Y_^[
Y_^[
h<O@
V9P
j h
t"+
tY+
t!Ht
wdS
Gd3
QSV
ruS
r>P
_^[
YH]
u}h
tG9
t?P
t)P
_^3
_^]
j"Y
_^[]
t'Ou
jPf
j"Y
_^]
j"Y
j"Y
_^]
A#E
woVW
@Pj
u&j
u^9
t@V
_^]
t8V
_^]
L8$
@l3
PPj
Yf;
t)j
Yf;
^;M
^;M
VVhU
PVh
t-j
t1S
VW;
9]$u
9](SS
~Cj
SSW
E ;
~Bj
t"SS9] u
_^[
9] SS
?Pj
_^[
F0;
v4;5|
Y^]
F ;
F$;
F8;
F<;
F@;
FD;
FH;
vL;5
Y^]
A f
A0f
A@f
APf
A`f
AHu
AJu
SVWUj
]_^[
P(R
P$R
SVW
UPj
D$(
|$,
;t$,v-
_^[
UQPXY]Y[
^_u
`q@
tp@
pq@
`q@
`q@
`q@
Wq@
Dq@
<q@
4q@
,q@
$q@
`q@
pq@
xq@
4r@
\r@
$s@
8s@
YY;
_^]
~%9M
| 3
QVj
r 8^
VW;
|[;
_^[]
u5j
oV f
o^0f
W f
_0f
of@f
onPf
ov`f
o~pf
g@f
oPf
w`f
FGIu
X^_]
FGIu
PPj
@hp
PPPPPPPP
t&:a
PPPPPPPP
WVS
[^_
0D@
pn@
!&@
(null)
EEE
( 8PX
700WP
`h````
xpxxxx
CorExitProcess
FlsFree
FlsSetValue
FlsGetValue
FlsAlloc
HH:mm:ss
dddd, MMMM dd, yyyy
MM/dd/yy
December
November
October
September
August
July
June
April
March
February
January
Dec
Nov
Oct
Sep
Aug
Jul
Jun
May
Apr
Mar
Feb
Jan
Saturday
Friday
Thursday
Wednesday
Tuesday
Monday
Sunday
Sat
Fri
Thu
Wed
Tue
Mon
Sun
EEE
('8PW
700PP
`h`hhh
xppwpp
GetProcessWindowStation
GetUserObjectInformationW
GetLastActivePopup
GetActiveWindow
MessageBoxW
 !"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
.;@
%@@
{G@
\O@
`O@
IQ@
Tl@
;x@
GetCommandLineA
HeapSetInformation
EnterCriticalSection
LeaveCriticalSection
DecodePointer
UnhandledExceptionFilter
SetUnhandledExceptionFilter
IsDebuggerPresent
EncodePointer
TerminateProcess
GetCurrentProcess
GetProcAddress
GetModuleHandleW
ExitProcess
WriteFile
GetStdHandle
GetModuleFileNameW
GetModuleFileNameA
FreeEnvironmentStringsW
WideCharToMultiByte
GetEnvironmentStringsW
SetHandleCount
InitializeCriticalSectionAndSpinCount
GetFileType
GetStartupInfoW
DeleteCriticalSection
TlsAlloc
TlsGetValue
TlsSetValue
TlsFree
InterlockedIncrement
SetLastError
GetCurrentThreadId
GetLastError
InterlockedDecrement
HeapCreate
QueryPerformanceCounter
GetTickCount
GetCurrentProcessId
GetSystemTimeAsFileTime
Sleep
HeapFree
GetCPInfo
GetACP
GetOEMCP
IsValidCodePage
RtlUnwind
LoadLibraryW
HeapAlloc
HeapReAlloc
GetConsoleCP
GetConsoleMode
FlushFileBuffers
LCMapStringW
MultiByteToWideChar
GetStringTypeW
SetFilePointer
IsProcessorFeaturePresent
HeapSize
CloseHandle
WriteConsoleW
SetStdHandle
CreateFileW
KERNEL32.dll
2beIWc5RAZj28D4kiK0c1WCtEeRvkb03il6t+ANP474tTZC4
                          
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
                          
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
1#1/151G1O1Z1
1f2l2
3#313F3P3v3
4V4h4
515<5$6
7`7o7
=V=
3(3.3k3
4b4<5D5\5w5
5"6(656;6D6K6m6
7)7.7J7T7j7u7
82898S8Z8
8'9:9L9
9 :-:B:s:
;t<
=,=7=
?!?
#0/0I0o0u0
1G1Q1|1
2F2i2o2
3$3,323>3D3Q3[3a3k3
484>4D4Z4r4
555?5w5
6 6%6-666B6G6L6R6V6\6a6g6l6{6
7&7J7V7f7
8'8^8g8s8
959>9e9r9w9
9`:
;G;N;X;j;
<2<r<
=2=
0G0R0\0u0
0"151
2z2
3-3?3Z3b3j3
424C4W4
4:5
5Q6
7"7[7
:Z;
<0<
>??v?|?
2070q0v0}0
1i2n2w2
2#3F3Q3W3g3l3}3
3'4A4[4]6d6j6a7
7"8(828
:b:
;%;
<><
70V0
0%1M1
2G2Q2
3x4
:+:=:O:a:s:
:3;@;Y;w;
;e<
=#=/=8===C=M=V=a=m=r=
=t>y>
>u?
0L0d0k0s0x0|0
1Z1`1d1h1l1
2-2W2
3x3~3
3#4U4}4
5*5I5
5_6
7l7
7#8.8\8j8
1(1,1d:l:t:|:
:$:(:H:h:t:
; ;@;`;|;
< <@<`<
80@0
; ;$;(;,;0;4;8;<;@;D;H;L;P;T;X;\;`;d;h;l;p;
< <$<(<
= =$=(=,=0=H=L=P=T=X=\=`=d=h=l=x=|=

Viram? em 3 minutos, de um programa nativo, encontrei algo suspeito que se parece com uma senha (neste caso, “2beIWc5RAZj28D4kiK0c1WCtEeRvkb03il6t+ANP474tTZC4”.)

[quote=bezier curve][quote=gomesrod]

Uma das opções mais seguras que vi aqui no tópico foi colocar o segredo em um programa nativo…[/quote]

Será?

Experimente fazer o seguinte: compile o seguinte programa em C:

Agora, usando o programa “strings” (é um programa que varre qualquer arquivo binário ou texto e separa as strings) você vai ter a seguinte saída
[/quote]

É, eu tinha idéia que se o programa usasse a string literal ela iria bonitinha para o executável.

O que eu pensei - mas não falei - era que esse programa em C deveria construir a string de um jeito maluco em tempo de execução.

Aqui vai um exemplo bobo, talvez seja até fácil de quebrar para alguém com os conhecimento necessários, mas daria para aumentar a complexidade até níveis bem altos:

#include <stdio.h>
#include <string.h>
#include <math.h>

int data1[] = {1,45, 109, 312, 2, 4, 5, 8, 98, 23, 981, 7, 49, 2, 3, 4, 100, 5};
int data2[] = {9, 12, 1023, 987, 900, 438, 939, 88, 111, 20, 23, 12, 98, 49, 15, 2039};

int main() {
        char buff[4];
        memset(buff, data1[1] + data2[9], 1);
        memset(buff+1, (data2[8] / data1[4]) + (data2[7] / data1[7]), 1);
        memset(buff+2, (int)(sqrt(data2[data1[5]]) * log10(*(data1+16)) + data1[11]), 1);

        memset(buff+3, 0, 1);

        // O segredo é "ABC"
        printf("%s\n", buff);
}

Só que mesmo assim nada impede alguém de simplesmente invocar o programa e obter o seu segredo!

so uma coisa sobre o uso de Hashs para armazenar senhas, NÃO use MD5 nem SHA-1, eles são algoritmos extremamente velhos e muito suscetíveis a brute force, em questão de minutos de recupera a senha de um MD5 e o SHA-1 demora um pouco mais.

Usem pelo menos SHA-2(256) com salt (valor constante adcionado a final da string a ser hasheada), assim impossibilita-se um brute force e torna impossível um ataque via rainbow table(tabela pré compilada de valores hasheados).

Pois é - normalmente muitos programas tentam usar código que inibe você debugar o programa - veja em http://pferrie.host22.com/papers/antidebug.pdf - mas mesmo assim não há muito o que possa ser feito contra alguém que tenha tempo e/ou paciência e/ou conhecimento suficiente.

Já vi várias formas de contornar isso (e todas me parecem gambiarras). Exemplos:

  • Criar uma DLL (no caso de Windows) que tenha um método exposto que retorna a senha (é só chamar o método e pronto, a senha está lá)
  • Criar um arquivo criptografado onde esses dados serão armazenados (as chaves de segurança ficarão, de alguma forma, expostas no aplicativo)

Outras soluções que foram levantadas foram o uso de certificados digitais (que não foram aprovados e nem sei se seriam viáveis).

No fim, vale mais o que o ViniGodoy disse. Se alguém conseguir acesso a essas informações, a falha na segurança é muito maior do que simplesmente expor o user/password da base de dados.