Sa mga application ng server, ang isa sa pinakamahalagang tagapagpahiwatig ay ang seguridad. Ito ay isa sa mga uri ng Non-Functional Requirements . Ang seguridad ay may maraming bahagi. Siyempre, upang ganap na masakop ang lahat ng mga proteksiyon na prinsipyo at aksyon na alam, kailangan mong magsulat ng higit sa isang artikulo, kaya tumuon tayo sa pinakamahalaga. Ang isang taong bihasa sa paksang ito, ay magagawang i-set up ang lahat ng mga proseso at matiyak na hindi sila lumikha ng mga bagong butas sa seguridad, ay kinakailangan sa anumang koponan. Siyempre, hindi mo dapat isipin na kung susundin mo ang mga kasanayang ito, magiging ganap na ligtas ang application. Hindi! Ngunit tiyak na magiging mas ligtas sa kanila. Pumunta ka.
1. Magbigay ng seguridad sa antas ng wikang Java
Una sa lahat, ang seguridad sa Java ay nagsisimula mismo sa antas ng feature ng wika. Ito ang gagawin natin kung walang access modifiers?... Anarchy, no less. Tinutulungan kami ng isang programming language na magsulat ng secure na code at samantalahin din ang maraming implicit na feature ng seguridad:- Malakas magtype. Ang Java ay isang statically typed na wika na nagbibigay ng kakayahang makakita ng mga error sa uri sa oras ng pagtakbo.
- I-access ang mga modifier. Salamat sa kanila, maaari naming i-configure ang access sa mga klase, pamamaraan at mga field ng klase sa paraang kailangan namin.
- Awtomatikong pamamahala ng memorya. Para sa layuning ito, kami (Javaists ;)) ay mayroong Garbage Collector, na nagpapalaya sa iyo mula sa manu-manong configuration. Oo, minsan may mga problema.
- Pagsusuri ng Bytecode: Nag-compile ang Java sa bytecode, na sinusuri ng runtime bago ito patakbuhin.
- Iwasang mag-serialize ng mga secure-sensitive na klase. Sa kasong ito, maaari mong makuha ang interface ng klase mula sa serialized na file, hindi banggitin ang data na ini-serialize.
- Subukang iwasan ang mga nababagong klase ng data. Ibinibigay nito ang lahat ng benepisyo ng mga hindi nababagong klase (hal. kaligtasan ng thread). Kung mayroong nababagong bagay, maaari itong humantong sa hindi inaasahang pag-uugali.
- Gumawa ng mga kopya ng ibinalik na nababagong mga bagay. Kung ang isang pamamaraan ay nagbabalik ng isang reference sa isang panloob na nababago na bagay, maaaring baguhin ng code ng kliyente ang panloob na estado ng bagay.
- At iba pa…
2. Tanggalin ang kahinaan ng SQL injection
Natatanging kahinaan. Ang pagiging natatangi nito ay nakasalalay sa katotohanan na ito ay parehong isa sa pinakasikat at isa sa mga pinakakaraniwang kahinaan. Kung hindi ka interesado sa isyu ng seguridad, hindi mo malalaman ang tungkol dito. Ano ang SQL injection? Ito ay isang pag-atake sa isang database sa pamamagitan ng pag-iniksyon ng karagdagang SQL code kung saan hindi ito inaasahan. Sabihin nating mayroon kaming isang paraan na nangangailangan ng ilang parameter upang i-query ang database. Halimbawa, username. Ang code na may kahinaan ay magiging ganito ang hitsura:// Метод достает из базы данных всех пользователей с определенным именем
public List<User> findByFirstName(String firstName) throws SQLException {
// Создается связь с базой данных
Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);
// Пишем sql request в базу данных с нашим firstName
String query = "SELECT * FROM USERS WHERE firstName = " + firstName;
// выполняем request
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery(query);
// при помощи mapToUsers переводит ResultSet в коллекцию юзеров.
return mapToUsers(result);
}
private List<User> mapToUsers(ResultSet resultSet) {
//переводит в коллекцию юзеров
}
Sa halimbawang ito, ang sql query ay inihanda nang maaga sa isang hiwalay na linya. Mukhang kung ano ang problema, tama ba? Siguro ang problema ay na ito ay mas mahusay na gamitin String.format
? Hindi? Ano ngayon? Ilagay natin ang ating sarili sa lugar ng isang tester at isipin kung ano ang maaaring maihatid sa halaga firstName
. Halimbawa:
- Maaari mong ipasa ang inaasahan - ang username. Pagkatapos ay ibabalik ng database ang lahat ng mga gumagamit na may ganoong pangalan.
- Maaari kang magpasa ng walang laman na string: pagkatapos ay ibabalik ang lahat ng user.
- O maaari mong ipasa ang sumusunod: “''; DROP TABLE USERS;”. At dito magkakaroon ng mas malalaking problema. Aalisin ng query na ito ang talahanayan mula sa database. Sa lahat ng data. LAHAT.
// Метод достает из базы данных всех пользователей с определенным именем
public List<User> findByFirstName(String firstName) throws SQLException {
// Создается связь с базой данных
Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);
// Создаем параметризированный request.
String query = "SELECT * FROM USERS WHERE firstName = ?";
// Создаем подготовленный стейтмент с параметризованным requestом
PreparedStatement statement = connection.prepareStatement(query);
// Передаем meaning параметра
statement.setString(1, firstName);
// выполняем request
ResultSet result = statement.executeQuery(query);
// при помощи mapToUsers переводим ResultSet в коллекцию юзеров.
return mapToUsers(result);
}
private List<User> mapToUsers(ResultSet resultSet) {
//переводим в коллекцию юзеров
}
Sa ganitong paraan, maiiwasan ang kahinaang ito. Para sa mga gustong sumabak nang mas malalim sa isyu kaysa sa artikulong ito, narito ang isang magandang halimbawa . Paano mo malalaman kung naiintindihan mo ang bahaging ito? Kung ang biro sa ibaba ay naging malinaw, kung gayon ito ay isang tiyak na senyales na ang kakanyahan ng kahinaan ay malinaw: D
3. I-scan at panatilihing na-update ang mga dependency
Ano ang ibig sabihin nito? Para sa mga hindi alam kung ano ang dependency, ipapaliwanag ko: ito ay isang jar archive na may code na nakakonekta sa isang proyekto gamit ang mga awtomatikong build system (Maven, Gradle, Ant) upang magamit muli ang solusyon ng ibang tao. Halimbawa, Project Lombok , na bumubuo ng mga getter, setter, atbp. para sa amin sa runtime. At kung pag-uusapan natin ang tungkol sa malalaking application, gumagamit sila ng maraming iba't ibang dependency. Ang ilan ay palipat (iyon ay, ang bawat dependency ay maaaring magkaroon ng sarili nitong mga dependency, at iba pa). Samakatuwid, ang mga umaatake ay lalong binibigyang pansin ang mga open-source na dependency, dahil ang mga ito ay regular na ginagamit at maaaring magdulot ng mga problema para sa maraming mga kliyente. Mahalagang tiyakin na walang kilalang mga kahinaan sa buong dependency tree (na kung ano mismo ang hitsura nito). At mayroong ilang mga paraan upang gawin ito.Gamitin ang Snyk para sa pagsubaybay
Sinusuri ng tool ng Snyk ang lahat ng mga dependency ng proyekto at nagba-flag ng mga kilalang kahinaan. Doon maaari kang magparehistro at mag-import ng iyong mga proyekto sa pamamagitan ng GitHub, halimbawa. Gayundin, tulad ng nakikita mo mula sa larawan sa itaas, kung ang isang mas bagong bersyon ay may solusyon sa kahinaang ito, mag-aalok ang Snyk na gawin ito at lumikha ng isang Pull-Request. Maaari itong magamit nang walang bayad para sa mga open-source na proyekto. Ang mga proyekto ay i-scan sa ilang dalas: isang beses sa isang linggo, isang beses sa isang buwan. Nagrehistro ako at idinagdag ang lahat ng aking mga pampublikong repositoryo sa Snyk scan (walang mapanganib tungkol dito: bukas na sila sa lahat). Susunod, ipinakita ni Snyk ang resulta ng pag-scan: At pagkaraan ng ilang sandali, naghanda ang Snyk-bot ng ilang Pull-Request sa mga proyekto kung saan kailangang i-update ang mga dependency: At narito ang isa pa: Kaya ito ay isang mahusay na tool para sa paghahanap ng mga kahinaan at pagsubaybay para sa pag-update mga bagong bersyon.Gamitin ang GitHub Security Lab
Magagamit din ng mga nagtatrabaho sa GitHub ang kanilang mga built-in na tool. Maaari kang magbasa nang higit pa tungkol sa diskarteng ito sa aking pagsasalin mula sa kanilang blog na Announcement of GitHub Security Lab . Ang tool na ito, siyempre, ay mas simple kaysa sa Snyk, ngunit tiyak na hindi mo ito dapat pabayaan. Dagdag pa, ang bilang ng mga kilalang kahinaan ay lalago lamang, kaya parehong lalawak at mapabuti ang Snyk at GitHub Security Lab.I-activate ang Sonatype DepShield
Kung gumagamit ka ng GitHub upang iimbak ang iyong mga repositoryo, maaari kang magdagdag ng isa sa mga application sa iyong mga proyekto mula sa MarketPlace - Sonatype DepShield. Sa tulong nito, maaari mo ring i-scan ang mga proyekto para sa mga dependency. Bukod dito, kung may mahanap ito, isang GitHub Issue ang gagawin na may kaukulang paglalarawan, tulad ng ipinapakita sa ibaba:4. Pangasiwaan ang sensitibong data nang may pag-iingat
Sa pagsasalita sa Ingles, ang pariralang "sensitive data" ay mas karaniwan. Ang pagsisiwalat ng personal na impormasyon, mga numero ng credit card at iba pang personal na impormasyon ng kliyente ay maaaring magdulot ng hindi na mapananauli na pinsala. Una sa lahat, kailangan mong tingnang mabuti ang disenyo ng application at matukoy kung ang anumang data ay talagang kailangan. Marahil ay hindi na kailangan ang ilan sa kanila, ngunit sila ay idinagdag para sa isang hinaharap na hindi pa dumarating at malamang na hindi darating. Bilang karagdagan, sa panahon ng pag-log ng proyekto, ang naturang data ay maaaring tumagas. Ang isang simpleng paraan upang pigilan ang sensitibong data na makapasok sa iyong mga log ay upang linisin ang mga pamamaraantoString()
ng mga entity ng domain (gaya ng User, Student, Teacher, at iba pa). Pipigilan nito ang mga sensitibong field na hindi sinasadyang ma-print. Kung gagamit ka ng Lombok upang makabuo ng paraan toString()
, maaari kang gumamit ng anotasyon @ToString.Exclude
upang maiwasan ang paggamit ng field sa output sa pamamagitan ng pamamaraan toString()
. Gayundin, maging maingat kapag nagbabahagi ng data sa labas ng mundo. Halimbawa, mayroong http endpoint na nagpapakita ng mga pangalan ng lahat ng user. Hindi na kailangang ipakita ang panloob na natatanging ID ng user. Bakit? Dahil sa paggamit nito, ang isang umaatake ay makakakuha ng iba, mas kumpidensyal na impormasyon tungkol sa bawat user. Halimbawa, kung gagamitin mo ang Jackson para i-serialize at i-deserialize ang mga POJO sa JSON , maaari mong gamitin ang @JsonIgnore
at mga anotasyon @JsonIgnoreProperties
upang maiwasang ma-serialize at deserialize ang mga partikular na field. Sa pangkalahatan, kailangan mong gumamit ng iba't ibang klase ng POJO para sa iba't ibang lugar. Ano ang ibig sabihin nito?
- Upang gumana sa database, gumamit lamang ng POJO - Entity.
- Upang gumana sa lohika ng negosyo, ilipat ang Entity sa Modelo.
- Upang makipagtulungan sa labas ng mundo at magpadala ng mga kahilingan sa http, gumamit ng mga ikatlong entity - DTO.
Gumamit ng malakas na encryption at hashing algorithm
Ang kumpidensyal na data ng customer ay dapat na ligtas na naka-imbak. Upang gawin ito kailangan mong gumamit ng pag-encrypt. Depende sa gawain, kailangan mong magpasya kung anong uri ng pag-encrypt ang gagamitin. Dagdag pa, ang mas malakas na pag-encrypt ay tumatagal ng mas maraming oras, kaya muli kailangan mong isaalang-alang kung gaano karaming ang pangangailangan para dito ay nagbibigay-katwiran sa oras na ginugol dito. Siyempre, maaari mong isulat ang algorithm sa iyong sarili. Ngunit ito ay hindi kailangan. Maaari mong samantalahin ang mga kasalukuyang solusyon sa lugar na ito. Halimbawa, ang Google Tink :<!-- https://mvnrepository.com/artifact/com.google.crypto.tink/tink -->
<dependency>
<groupId>com.google.crypto.tink</groupId>
<artifactId>tink</artifactId>
<version>1.3.0</version>
</dependency>
Tingnan natin kung paano ito gamitin, gamit ang halimbawa kung paano i-encrypt ang isang paraan at ang isa pa:
private static void encryptDecryptExample() {
AeadConfig.register();
KeysetHandle handle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_CTR_HMAC_SHA256);
String plaintext = "Цой жив!";
String aad = "Юрий Клинских";
Aead aead = handle.getPrimitive(Aead.class);
byte[] encrypted = aead.encrypt(plaintext.getBytes(), aad.getBytes());
String encryptedString = Base64.getEncoder().encodeToString(encrypted);
System.out.println(encryptedString);
byte[] decrypted = aead.decrypt(Base64.getDecoder().decode(encrypted), aad.getBytes());
System.out.println(new String(decrypted));
}
Pag-encrypt ng password
Para sa gawaing ito, pinakaligtas na gumamit ng asymmetric encryption. Bakit? Dahil ang application ay talagang hindi kailangang i-decrypt ang mga password pabalik. Ito ang pangkalahatang diskarte. Sa totoo lang, kapag nagpasok ang isang user ng password, ine-encrypt ito ng system at ikinukumpara ito sa kung ano ang nasa vault ng password. Isinasagawa ang pag-encrypt gamit ang parehong paraan, kaya maaari mong asahan na magkatugma ang mga ito (kung ipinasok mo ang tamang password ;), siyempre). Ang BCrypt at SCrypt ay angkop para sa layuning ito. Parehong one-way na function (cryptographic hashes) na may computationally complex algorithm na tumatagal ng maraming oras. Ito ay eksakto kung ano ang kailangan mo, dahil ang pag-decipher nito nang direkta ay magtatagal magpakailanman. Halimbawa, sinusuportahan ng Spring Security ang isang hanay ng mga algorithm.SCryptPasswordEncoder
Maaari mo ring gamitin ang BCryptPasswordEncoder
. Ano ang isang malakas na algorithm ng pag-encrypt ngayon ay maaaring mahina sa susunod na taon. Bilang resulta, napagpasyahan namin na kinakailangang suriin ang mga algorithm na ginamit at i-update ang mga aklatan gamit ang mga algorithm.
Sa halip na output
Ngayon napag-usapan natin ang tungkol sa kaligtasan at, siyempre, maraming bagay ang naiwan sa mga eksena. Binuksan ko lang ang pinto sa isang bagong mundo para sa iyo: isang mundo na may sariling buhay. Sa seguridad ay kapareho ng sa pulitika: kung hindi ka nakikisali sa pulitika, ang pulitika ay sasali sa iyo. Ayon sa kaugalian, iminumungkahi kong mag-subscribe sa aking Github account . Doon ko ipino-post ang aking trabaho sa iba't ibang teknolohiya na aking pinag-aaralan at inilalapat sa trabaho.kapaki-pakinabang na mga link
Oo, halos lahat ng mga artikulo sa site ay nakasulat sa Ingles. Gustuhin man natin o hindi, ang Ingles ay ang wika para sa mga programmer na makipag-usap. Ang lahat ng pinakabagong artikulo, aklat, at magasin sa programming ay nakasulat sa Ingles. Iyon ang dahilan kung bakit ang aking mga link sa mga rekomendasyon ay halos nasa English:- Habr: SQL Injection para sa mga Nagsisimula
- Oracle: Java Security Resource Center
- Oracle: Secure Coding Guidelines para sa Java SE
- Baeldung: Ang Mga Pangunahing Kaalaman ng Java Security
- Katamtaman: 10 tip para palakasin ang iyong seguridad sa Java
- Snyk: 10 pinakamahusay na kasanayan sa seguridad ng java
- JR: Anunsyo ng GitHub Security Lab: sabay na nagpoprotekta sa lahat ng iyong code
GO TO FULL VERSION