Skip to content

Commit 6266c19

Browse files
committed
Do not allow any insecure deserialization but the one downloaded
1 parent a878e00 commit 6266c19

File tree

1 file changed

+64
-9
lines changed

1 file changed

+64
-9
lines changed

src/main/java/org/hdivsamples/controllers/DashboardController.java

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010
import java.io.ObjectOutputStream;
1111
import java.io.OutputStream;
1212
import java.net.URL;
13+
import java.security.MessageDigest;
14+
import java.security.NoSuchAlgorithmException;
1315
import java.security.Principal;
1416
import java.util.List;
1517

1618
import javax.servlet.http.HttpServletResponse;
1719

20+
import org.apache.commons.io.IOUtils;
1821
import org.hdivsamples.bean.Account;
1922
import org.hdivsamples.bean.CashAccount;
2023
import org.hdivsamples.bean.CreditAccount;
@@ -51,6 +54,8 @@ public class DashboardController {
5154
@Autowired
5255
StorageFacade storageFacade;
5356

57+
private String checksum;
58+
5459
@RequestMapping
5560
public String activity(final Model model, final Principal principal) {
5661

@@ -94,14 +99,13 @@ public void getImage(final HttpServletResponse response, @RequestParam(value = "
9499
}
95100

96101
@RequestMapping(value = "/userDetail/creditCardImage", method = RequestMethod.GET)
97-
public void getCreditCardImage(@RequestParam(value = "url") final String image, HttpServletResponse response) throws IOException {
102+
public void getCreditCardImage(@RequestParam(value = "url") final String image, final HttpServletResponse response) throws IOException {
98103
String downLoadImgFileName = InsecureBankUtils.getNameWithoutExtension(image) + "." + InsecureBankUtils.getFileExtension(image);
99104
// download
100-
response.setHeader( "content-disposition", "attachment;fileName=" + downLoadImgFileName);
105+
response.setHeader("content-disposition", "attachment;fileName=" + downLoadImgFileName);
101106
URL u = new URL(image);
102-
writeResponse(u.openStream(),response.getOutputStream());
107+
writeResponse(u.openStream(), response.getOutputStream());
103108
}
104-
105109

106110
@RequestMapping(value = "/userDetail/avatar/update", method = RequestMethod.POST)
107111
public String updateAvatar(@RequestParam("imageFile") final MultipartFile imageFile, final Principal principal,
@@ -150,13 +154,28 @@ public void getCertificate(final HttpServletResponse response, final Account acc
150154
@RequestMapping(value = "/userDetail/newcertificate", method = RequestMethod.POST)
151155
@ResponseBody
152156
public String processSimple(@RequestParam(value = "file", required = false) final MultipartFile file, final Model model)
153-
throws IOException, ClassNotFoundException {
157+
throws IOException, ClassNotFoundException, NoSuchAlgorithmException {
158+
File tmpFile = File.createTempFile("serial", ".ser");
159+
file.transferTo(tmpFile);
160+
161+
// Use MD5 algorithm
162+
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
163+
164+
// Get the checksum
165+
String uploadChecksum = getFileChecksum(md5Digest, tmpFile);
154166

155-
ObjectInputStream ois = new ObjectInputStream(file.getInputStream());
156-
ois.readObject();
157-
ois.close();
167+
if (uploadChecksum.equals(checksum)) {
158168

159-
return "<p>File '" + file.getOriginalFilename() + "' uploaded successfully</p>";
169+
IOUtils.copy(file.getInputStream(), new FileOutputStream(tmpFile));
170+
ObjectInputStream ois = new ObjectInputStream(file.getInputStream());
171+
ois.readObject();
172+
ois.close();
173+
174+
return "<p>File '" + file.getOriginalFilename() + "' uploaded successfully</p>";
175+
}
176+
else {
177+
return "<p>File '" + file.getOriginalFilename() + "' not processed, only previously downloaded malicious file is allowed</p>";
178+
}
160179
}
161180

162181
@RequestMapping(value = "/userDetail/maliciouscertificate", method = RequestMethod.POST)
@@ -176,6 +195,12 @@ public void getMaliciousCertificate(final HttpServletResponse response, final Ac
176195
oos.close();
177196
fos.close();
178197

198+
// Use MD5 algorithm
199+
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
200+
201+
// Get the checksum
202+
checksum = getFileChecksum(md5Digest, tmpFile);
203+
179204
// Write into response
180205

181206
response.setHeader("Content-Disposition", "attachment; filename=\"MaliciousCertificate" + bdAccount.getName() + "_" + ".jks\"");
@@ -190,6 +215,36 @@ public void getMaliciousCertificate(final HttpServletResponse response, final Ac
190215

191216
}
192217

218+
private static String getFileChecksum(final MessageDigest digest, final File file) throws IOException {
219+
// Get file input stream for reading the file content
220+
FileInputStream fis = new FileInputStream(file);
221+
222+
// Create byte array to read data in chunks
223+
byte[] byteArray = new byte[1024];
224+
int bytesCount = 0;
225+
226+
// Read file data and update in message digest
227+
while ((bytesCount = fis.read(byteArray)) != -1) {
228+
digest.update(byteArray, 0, bytesCount);
229+
}
230+
231+
// close the stream; We don't need it now.
232+
fis.close();
233+
234+
// Get the hash's bytes
235+
byte[] bytes = digest.digest();
236+
237+
// This bytes[] has bytes in decimal format;
238+
// Convert it to hexadecimal format
239+
StringBuilder sb = new StringBuilder();
240+
for (int i = 0; i < bytes.length; i++) {
241+
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
242+
}
243+
244+
// return complete hash
245+
return sb.toString();
246+
}
247+
193248
private int writeResponse(final InputStream is, final OutputStream out) {
194249
int total = 0;
195250
try {

0 commit comments

Comments
 (0)