Pambuka
Ing review iki aku pengin ngrembug topik kayata keamanan aplikasi web. Jawa nduweni sawetara teknologi sing nyedhiyakake keamanan:-
" Arsitektur Keamanan Platform Java SE ", rincian liyane babagan sing bisa diwaca ing Pandhuan saka Oracle: " Arsitektur Keamanan Platform JavaTM SE ". Arsitèktur iki njlèntrèhaké carane kita kudu ngamanake aplikasi Java ing lingkungan runtime Java SE. Nanging iki dudu topik obrolan kita saiki.
-
" Arsitektur Kriptografi Jawa " yaiku Ekstensi Jawa sing nggambarake enkripsi data. Sampeyan bisa maca liyane babagan ekstensi iki ing JavaRush ing review " Java Cryptography Architecture: First acquaintance " utawa ing Pandhuan saka Oracle: " Java Cryptography Architecture (JCA) Reference Guide ".
JAAS
JAAS minangka extension kanggo Java SE lan diterangake ing Java Authentication and Authorization Service (JAAS) Reference Guide . Minangka jeneng teknologi kasebut, JAAS nerangake carane otentikasi lan wewenang kudu ditindakake:-
" Authentication ": Diterjemahake saka basa Yunani, "authentikos" tegese "nyata, asli". Tegese, otentikasi minangka tes keaslian. Sing sapa sing diotentikasi iku sejatine sing diomongake.
-
" Wewenang ": diterjemahake saka basa Inggris tegese "ijin". Tegese, wewenang yaiku kontrol akses sing ditindakake sawise otentikasi sukses.
- SIM kang minangka perwakilan saka wong minangka pangguna dalan
- passport, minangka perwakilan saka wong minangka warga negara kang
- passport manca kang, minangka perwakilan saka wong minangka peserta ing hubungan internasional
- kertu perpustakaan ing perpustakaan, minangka perwakilan saka wong minangka maca ditempelake perpustakaan
Aplikasi web
Dadi, kita butuh aplikasi web. Sistem mbangun proyek otomatis Gradle bakal mbantu kita nggawe. Thanks kanggo panggunaan Gradle, kita bisa, kanthi nglakokake perintah cilik, ngumpulake proyek Java ing format sing dibutuhake, kanthi otomatis nggawe struktur direktori sing dibutuhake, lan liya-liyane. Sampeyan bisa maca liyane babagan Gradle ing ringkesan singkat: " A Brief Pambuka kanggo Gradle " utawa ing dokumentasi resmi " Gradle Miwiti ". Kita kudu miwiti proyek kasebut (Initialization), lan kanggo tujuan iki Gradle duwe plugin khusus: " Gradle Init Plugin " (Init singkatan saka Initialization, gampang dieling-eling). Kanggo nggunakake plugin iki, jalanake printah ing baris printah:gradle init --type java-application
Sawise rampung, kita bakal duwe proyek Java. Ayo saiki mbukak skrip mbangun proyek kita kanggo nyunting. Skrip mbangun yaiku file sing diarani build.gradle
, sing nggambarake nuansa saka mbangun aplikasi. Mula jenenge, mbangun skrip. Kita bisa ngomong yen iki minangka skrip mbangun proyek. Gradle minangka alat serbaguna, kemampuan dhasar sing ditambahi karo plugin. Mulane, pisanan, ayo menehi perhatian marang blok "plugin":
plugins {
id 'java'
id 'application'
}
Kanthi gawan, Gradle, miturut apa sing wis ditemtokake " --type java-application
", wis nyiyapake sawetara plugin inti, yaiku, plugin kasebut sing kalebu ing distribusi Gradle dhewe. Yen sampeyan pindhah menyang bagean "Docs" (yaiku, dokumentasi) ing situs web gradle.org , banjur ing sisih kiwa ing dhaptar topik ing bagean "Referensi" kita ndeleng bagean " Inti Plugins ", yaiku. bagean kanthi katrangan babagan plugin dhasar iki. Ayo milih plugin sing dibutuhake, lan dudu plugin sing digawe Gradle kanggo kita. Miturut dokumentasi, " Gradle Java Plugin " nyedhiyakake operasi dhasar karo kode Jawa, kayata kompilasi kode sumber. Kajaba iku, miturut dokumentasi, " Gradle application plugin " nyedhiyakake alat kanggo nggarap "aplikasi JVM sing bisa dieksekusi", yaiku. karo aplikasi java sing bisa dibukak minangka aplikasi dewekan (contone, aplikasi console utawa aplikasi karo UI dhewe). Pranyata kita ora butuh plugin "aplikasi", amarga ... kita ora butuh aplikasi mandiri, kita butuh aplikasi web. Ayo dibusak. Uga setelan "mainClassName", sing mung dikenal kanggo plugin iki. Salajengipun, ing bagean " Pengemasan lan distribusi " sing padha karo link menyang dokumentasi Aplikasi Plugin diwenehake, ana link menyang Gradle War Plugin. Gradle War Plugin , kaya sing kasebut ing dokumentasi, nyedhiyakake dhukungan kanggo nggawe aplikasi web Java ing format perang. Ing format WAR tegese tinimbang arsip JAR, arsip WAR bakal digawe. Kayane iki sing kita butuhake. Uga, minangka dokumentasi ngandika, "Plugin Perang ngluwihi plugin Jawa". Yaiku, kita bisa ngganti plugin java karo plugin perang. Mula, blok plugin kita bakal katon kaya iki:
plugins {
id 'war'
}
Uga ing dokumentasi kanggo "Gradle War Plugin" ngandika sing plugin nggunakake tambahan "Project Layout". Tata letak diterjemahake saka basa Inggris minangka lokasi. Yaiku, plugin perang kanthi standar ngarepake anane lokasi file tartamtu sing bakal digunakake kanggo tugas kasebut. Bakal nggunakake direktori ing ngisor iki kanggo nyimpen file aplikasi web: src/main/webapp
Prilaku plugin kasebut diterangake kaya ing ngisor iki:
web.xml
- iki minangka "Deskriptor Penyebaran" utawa "deskriptor penyebaran". Iki minangka file sing nerangake carane ngatur aplikasi web supaya bisa digunakake. Berkas iki nemtokake panjaluk apa sing bakal ditindakake aplikasi kita, setelan keamanan, lan liya-liyane. Ing inti, iku meh padha karo file manifest saka file JAR (ndeleng " Nggarap File Manifest: Dasar "). File Manifest ngandhani carane nggarap Aplikasi Java (yaiku arsip JAR), lan web.xml nyritakake cara nggarap Aplikasi Web Java (yaiku arsip WAR). Konsep banget saka "Deskriptor Deployment" ora muncul dhewe, nanging diterangake ing dokumen " Spesifikasi API Servlet"". Sembarang aplikasi web Java gumantung ing "Servlet API" iki. Penting kanggo mangerteni yen iki minangka API - yaiku, minangka gambaran saka sawetara kontrak interaksi. Aplikasi web dudu aplikasi independen. Padha mlaku ing server web. , sing nyedhiyakake komunikasi jaringan karo pangguna. Yaiku, server web minangka jinis "wadhah" kanggo aplikasi web. Iki logis, amarga kita pengin nulis logika aplikasi web, yaiku kaca apa sing bakal dideleng pangguna lan kepiye carane padha kudu nanggepi tumindak pangguna. Lan kita ora pengin nulis kode kanggo carane pesen bakal dikirim menyang pangguna, carane bita informasi bakal ditransfer lan liyane tingkat kurang lan kualitas-nuntut banget. Kajaba iku, Pranyata aplikasi web kabeh beda, nanging transfer data padha. Yaiku, yuta programer kudu nulis kode kanggo tujuan sing padha bola-bali. Dadi server web tanggung jawab kanggo sawetara interaksi pangguna. lan ijol-ijolan data, lan aplikasi web lan pangembang tanggung jawab kanggo ngasilake data kasebut. Lan kanggo nyambungake rong bagean kasebut, yaiku. server web lan aplikasi web, sampeyan kudu kontrak kanggo interaksi, i.e. aturan apa bakal padha tindakake kanggo nindakake iki? Supaya bisa njlèntrèhaké kontrak, kaya apa interaksi antara aplikasi web lan server web, API Servlet diciptakake. Apike, sanajan sampeyan nggunakake kerangka kaya Spring, isih ana Servlet API sing mlaku ing ngisor hood. Yaiku, sampeyan nggunakake Spring, lan Spring bisa digunakake karo Servlet API kanggo sampeyan. Pranyata proyek aplikasi web kita kudu gumantung ing Servlet API. Ing kasus iki, Servlet API bakal dadi ketergantungan. Kaya sing wis dingerteni, Gradle uga ngidini sampeyan nggambarake dependensi proyek kanthi cara deklaratif. Plugins nerangake carane dependensi bisa diatur. Contone, Java Gradle Plugin ngenalake metode manajemen dependensi "testImplementation", sing ujar manawa dependensi kasebut mung dibutuhake kanggo tes. Nanging Gradle War Plugin nambahake metode manajemen dependensi "providedCompile", sing ujar manawa dependensi kasebut ora bakal kalebu ing arsip WAR aplikasi web kita. Napa kita ora kalebu Servlet API ing arsip WAR kita? Amarga API Servlet bakal diwenehake menyang aplikasi web kita dening server web kasebut dhewe. Yen server web nyedhiyakake API Servlet, server kasebut diarani wadhah servlet. Mulane, iku tanggung jawab saka server web kanggo nyedhiyani kita karo Servlet API, lan iku tanggung jawab kita kanggo nyedhiyani ServletAPI mung nalika kode wis nyawiji. Mulane providedCompile
. Dadi, blok dependensi bakal katon kaya iki:
dependencies {
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
testImplementation 'junit:junit:4.12'
}
Dadi, ayo bali menyang file web.xml. Kanthi gawan, Gradle ora nggawe Deskriptor Deployment, mula kita kudu nindakake iki dhewe. Ayo nggawe direktori src/main/webapp/WEB-INF
, lan ing kana kita bakal nggawe file XML sing diarani web.xml
. Saiki ayo mbukak "Java Servlet Specification" dhewe lan bab " BAB 14 Deployment Descriptor ". Kaya sing kasebut ing "14.3 Deskriptor Deskriptor", dokumen XML Deskriptor Deployment diterangake kanthi skema http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd . Skema XML njlèntrèhaké unsur apa sing bisa dumadi saka dokumen lan ing urutan apa sing kudu katon. Endi sing wajib lan sing ora. Umumé, iki njlèntrèhaké struktur dokumen lan ngidini sampeyan mriksa apa dokumen XML wis digawe kanthi bener. Saiki ayo gunakake conto saka bab " 14.5 Conto ", nanging skema kasebut kudu ditemtokake kanggo versi 3.1, i.e.
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd
Kita kosong web.xml
bakal katon kaya iki:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>JAAS Example</display-name>
</web-app>
Ayo saiki nggambarake servlet sing bakal kita lindungi nggunakake JAAS. Sadurunge, Gradle ngasilake kelas App kanggo kita. Ayo dadi servlet. Kaya sing kasebut ing spesifikasi ing " BAB 2 Antarmuka Servlet ", sing " Kanggo umume tujuan, Pangembang bakal ngluwihi HttpServlet kanggo ngleksanakake servlet ", yaiku, kanggo nggawe kelas servlet, sampeyan kudu oleh warisan kelas iki saka HttpServlet
:
public class App extends HttpServlet {
public String getGreeting() {
return "Secret!";
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print(getGreeting());
}
}
Kaya sing wis dakkandhakake, Servlet API minangka kontrak antarane server lan aplikasi web kita. Kontrak iki ngidini kita njlèntrèhaké manawa pangguna ngubungi server, server bakal ngasilake panjalukan saka pangguna ing wangun obyek HttpServletRequest
lan ngirim menyang servlet. Iku uga bakal nyedhiyani servlet karo obyek HttpServletResponse
supaya servlet bisa nulis respon kanggo pangguna. Sawise servlet wis rampung mlaku, server bakal bisa menehi pangguna respon adhedhasar iku HttpServletResponse
. Tegese, servlet ora langsung komunikasi karo pangguna, nanging mung karo server. Supaya server ngerti yen kita duwe servlet lan panjaluk apa sing kudu digunakake, kita kudu ngandhani server babagan iki ing deskriptor penyebaran:
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>jaas.App</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/secret</url-pattern>
</servlet-mapping>
Ing kasus iki, kabeh panjalukan /secret
ora bakal ditujokake menyang siji servlet kanthi jeneng app
, sing cocog karo kelas kasebut jaas.App
. Kaya sing wis dakkandhakake sadurunge, aplikasi web mung bisa dipasang ing server web. Server web bisa diinstal kanthi kapisah (mandiri). Nanging kanggo tujuan review iki, pilihan alternatif cocok - mlaku ing server sing dipasang. Iki tegese server bakal digawe lan diluncurake kanthi program (plugin bakal nindakake iki kanggo kita), lan ing wektu sing padha aplikasi web kita bakal disebarake. Sistem mbangun Gradle ngidini sampeyan nggunakake plugin " Gradle Gretty Plugin " kanggo tujuan kasebut:
plugins {
id 'war'
id 'org.gretty' version '2.2.0'
}
Kajaba iku, plugin Gretty duwe dokumentasi sing apik . Ayo diwiwiti kanthi kasunyatan manawa plugin Gretty ngidini sampeyan ngalih ing antarane server web sing beda. Iki diterangake kanthi luwih rinci ing dokumentasi: " Ngalih ing antarane wadhah servlet ". Ayo pindhah menyang Tomcat, amarga ... iku salah siji sing paling populer digunakake, lan uga wis dokumentasi apik lan akeh conto lan analisa masalah:
gretty {
// Переключаемся с дефолтного Jetty на Tomcat
servletContainer = 'tomcat8'
// Укажем Context Path, он же Context Root
contextPath = '/jaas'
}
Saiki kita bisa mbukak "gradle appRun" banjur aplikasi web kita bakal kasedhiya ing http://localhost:8080/jaas/secret
Authentication
Setelan otentikasi asring dumadi saka rong bagean: setelan ing sisih server lan setelan ing sisih aplikasi web sing mlaku ing server iki. Setelan keamanan aplikasi web ora bisa nanging sesambungan karo setelan keamanan server web, yen ora ana alesan liyane kajaba aplikasi web ora bisa sesambungan karo server web. Ora muspra yen kita pindhah menyang Tomcat, amarga ... Tomcat nduweni arsitektur sing diterangake kanthi apik (pirsani " Arsitektur Apache Tomcat 8 "). Saka gambaran arsitektur iki cetha yen Tomcat, minangka server web, nggambarake aplikasi web minangka konteks tartamtu, sing diarani " Konteks Tomcat ". Konteks iki ngidini saben aplikasi web duwe setelan dhewe, diisolasi saka aplikasi web liyane. Kajaba iku, aplikasi web bisa mengaruhi setelan konteks iki. Fleksibel lan trep. Kanggo pangerten sing luwih jero, disaranake maca artikel " Ngerti Kontainer Konteks Tomcat " lan bagean dokumentasi Tomcat " Kontainer Konteks ". Kaya sing kasebut ing ndhuwur, aplikasi web kita bisa mangaruhi Konteks Tomcat aplikasi kita nggunakake/META-INF/context.xml
. Lan salah sawijining setelan penting sing bisa kita pengaruhi yaiku Realms Keamanan. Realms Keamanan minangka jinis "area keamanan". Wilayah sing wis ditemtokake setelan keamanan tartamtu. Mula, nalika nggunakake Realm Keamanan, kita ngetrapake setelan keamanan sing ditetepake kanggo Realm iki. Realms Keamanan dikelola dening wadhah, i.e. server web, dudu aplikasi web kita. Kita mung bisa ngandhani server apa ruang lingkup keamanan sing kudu ditambahake menyang aplikasi kita. Dokumentasi Tomcat ing bagean " Komponen Realm " nggambarake Realm minangka kumpulan data babagan pangguna lan peran kanggo nindakake otentikasi. Tomcat nyedhiyakake sawetara implementasi Realm Keamanan sing beda-beda, salah sijine yaiku " Jaas Realm ". Sawise ngerti terminologi sethithik, ayo nerangake Konteks Tomcat ing file kasebut /META-INF/context.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="JaasLogin"
userClassNames="jaas.login.UserPrincipal"
roleClassNames="jaas.login.RolePrincipal"
configFile="jaas.config" />
</Context>
appName
- jeneng aplikasi. Tomcat bakal nyoba kanggo cocog jeneng iki karo jeneng sing ditemtokake ing configFile
. configFile
- iki "file konfigurasi login". Conto iki bisa dideleng ing dokumentasi JAAS: " Lampiran B: Conto Konfigurasi Login ". Kajaba iku, penting yen file iki bakal digoleki dhisik ing sumber daya. Mula, aplikasi web kita bisa nyedhiyakake file iki dhewe. Atribut userClassNames
lan roleClassNames
ngemot pratondo saka kelas sing makili principal pangguna. JAAS misahake konsep "pangguna" lan "peran" minangka rong konsep sing beda java.security.Principal
. Ayo digambarake kelas ing ndhuwur. Ayo nggawe implementasine paling gampang kanggo principal pangguna:
public class UserPrincipal implements Principal {
private String name;
public UserPrincipal(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
Kita bakal mbaleni persis implementasine padha kanggo RolePrincipal
. Nalika sampeyan bisa ndeleng saka antarmuka, bab utama kanggo Principal kanggo nyimpen lan bali sawetara jeneng (utawa ID) sing makili Principal. Saiki, kita duwe Realm Keamanan, kita duwe kelas utama. Iku tetep kanggo ngisi file saka configFile
atribut " ", alias login configuration file
. Katrangan kasebut bisa ditemokake ing dokumentasi Tomcat: " Komponen Alam ".
\src\main\resources\jaas.config
Ayo setel isi berkas iki:
JaasLogin {
jaas.login.JaasLoginModule required debug=true;
};
Wigati dicathet yen context.xml
jeneng sing padha digunakake ing kene lan ing. Iki peta Realm Keamanan menyang LoginModule. Dadi, Tomcat Context ngandhani kelas endi sing makili kepala sekolah, uga LoginModule sing digunakake. Kabeh sing kudu ditindakake yaiku ngleksanakake LoginModule iki. LoginModule bisa uga minangka salah sawijining perkara sing paling menarik ing JAAS. Dokumentasi resmi bakal mbantu kita ngembangake LoginModule: " Java Authentication and Authorization Service (JAAS): LoginModule Developer's Guide ". Ayo ngleksanakake modul login. Ayo nggawe kelas sing ngetrapake antarmuka LoginModule
:
public class JaasLoginModule implements LoginModule {
}
Pisanan kita njlèntrèhaké cara initialization LoginModule
:
private CallbackHandler handler;
private Subject subject;
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, <String, ?> sharedState, Map<String, ?> options) {
handler = callbackHandler;
this.subject = subject;
}
Cara iki bakal nyimpen Subject
, sing bakal kita keasliane lan isi informasi babagan kepala sekolah. Kita uga bakal nyimpen kanggo nggunakake mbesuk CallbackHandler
, kang diwenehi kanggo kita. Kanthi bantuan, CallbackHandler
kita bisa njaluk macem-macem informasi babagan subyek otentikasi mengko. Sampeyan bisa maca liyane babagan CallbackHandler
ing bagean cocog saka dokumentasi: " JAAS Reference Guide: CallbackHandler ". Sabanjure, cara login
kanggo otentikasi dieksekusi Subject
. Iki minangka fase pisanan otentikasi:
@Override
public boolean login() throws LoginException {
// Добавляем колбэки
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("login");
callbacks[1] = new PasswordCallback("password", true);
// При помощи колбэков получаем через CallbackHandler логин и пароль
try {
handler.handle(callbacks);
String name = ((NameCallback) callbacks[0]).getName();
String password = String.valueOf(((PasswordCallback) callbacks[1]).getPassword());
// Далее выполняем валидацию.
// Тут просто для примера проверяем определённые значения
if (name != null && name.equals("user123") && password != null && password.equals("pass123")) {
// Сохраняем информацию, которая будет использована в методе commit
// Не "пачкаем" Subject, т.к. не факт, что commit выполнится
// Для примера проставим группы вручную, "хардcodeно".
login = name;
userGroups = new ArrayList<String>();
userGroups.add("admin");
return true;
} else {
throw new LoginException("Authentication failed");
}
} catch (IOException | UnsupportedCallbackException e) {
throw new LoginException(e.getMessage());
}
}
Penting yen login
kita ora ngganti Subject
. Owah-owahan kasebut mung kudu kedadeyan ing cara konfirmasi commit
. Sabanjure, kita kudu njlèntrèhaké cara kanggo konfirmasi otentikasi sukses:
@Override
public boolean commit() throws LoginException {
userPrincipal = new UserPrincipal(login);
subject.getPrincipals().add(userPrincipal);
if (userGroups != null && userGroups.size() > 0) {
for (String groupName : userGroups) {
rolePrincipal = new RolePrincipal(groupName);
subject.getPrincipals().add(rolePrincipal);
}
}
return true;
}
Sampeyan bisa uga koyone aneh kanggo misahake cara login
lan commit
. Nanging titik iku modul login bisa digabungake. Lan kanggo otentikasi sukses bisa uga perlu sawetara modul login supaya bisa sukses. Lan mung yen kabeh modul sing dibutuhake wis digunakake, banjur simpen pangowahan kasebut. Iki fase kapindho otentikasi. Ayo rampung karo cara abort
lan logout
:
@Override
public boolean abort() throws LoginException {
return false;
}
@Override
public boolean logout() throws LoginException {
subject.getPrincipals().remove(userPrincipal);
subject.getPrincipals().remove(rolePrincipal);
return true;
}
Cara kasebut abort
diarani nalika fase pertama otentikasi gagal. Cara kasebut logout
diarani nalika sistem metu. Sawise ngetrapake kita Login Module
lan ngatur Security Realm
, Saiki kita kudu nuduhake web.xml
kasunyatan manawa kita pengin nggunakake sing spesifik Login Config
:
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>JaasLogin</realm-name>
</login-config>
Kita nemtokake jeneng Realm Keamanan lan nemtokake Cara Authentication - BASIC. Iki minangka salah sawijining jinis otentikasi sing diterangake ing Servlet API ing bagean " 13.6 Authentication ". Sisa n
GO TO FULL VERSION