-->

Do signed java applets have access to USB peripher

2019-02-19 16:02发布

问题:

I've implemented a Java package with functionality to operate a POS printer and cash drawer connected to the workstation via USB. I've also implemented an applet to utilize the functionality of this package with the hopes of having it invoked by a POS website.

When the applet is run from within Eclipse, all goes well. When the applet is run from within a browser it seems that my package is unable to access the peripherals connected via USB. I get an error from the third party (JavaPOS) code stating:

jpos.JposException: The device communications channel could not be opened, check the device and retry.

The applet is signed with a self-cert. I'd post some code but the error is thrown from somewhere buried in manufacturer-specific drivers for the POS printer in use.

I'm assuming the issue is that, from within the browser sandbox, the applet does not have access to the peripherals connected via USB.
Could this be the case? If so, is there anyway to access USB peripherals from within a signed Applet?
If an applet can't access USB peripherals, how could a web site invoke code that can?

回答1:

Do signed java applets have access to USB peripherals when run in the browser sandbox?

To address this specific question (and avoid the specific technologies involved in the comments following), yes Signed Java Applets have access to USB Peripherals. The "sandbox" is what you have capability to "break out of" when you run a signed applet.

But for security reasons, simply signing the applet does not automatically give access to items outside of the sandbox.

PrivelegedAction seems to be the preferred method for accessing privileged system components, such as the printer. More about these privileged actions is provided by Oracle here: http://docs.oracle.com/javase/7/docs/api/java/security/AccessController.html

In addition, there are several consideration when doing something like this from a web browser as Java cares where the action originates from.

public function writeFile() {
    ...
    FileWriter fw = new FileWriter(...);
    ...
}


public void init() {
    writeFile();
}

For example, if you were to write a file to the filesystem (i.e. $HOME/Desktop/text.txt) using the FileWriter class in the applet init() method, a Signed Applet would generally allow it. Wrapping this into a PrivilegedAction would be better, and checking permission first using AccessController.checkPermission(...) would be ideal.

However, FileWriter gets blocked when it's called directly from JavaScript (instead of from init()):

var myapplet = document.getElementById('myapplet');
myapplet.writeFile(); // Blocked by Security Framework

To circumvent this issue, some chose to use PrivelegedAction, however if the action takes a long time, you'll notice it blocks the UI, which is very bad practice in a web page (and can deadlock the browser).

public void init() {
   ...
   AccessController.doPrivileged(new PrivilegedAction() {
      public Object run() {
         writeFile();
         return null;
      }
   });
   ...
}

Furthermore, your question asks specifically about accessing a USB peripheral, which is generally done by iterating through the Human Interface Devices. HID is not something Java directly supports natively (yet, as of writing this/JRE7). So yes, a signed applet CAN talk to your USB peripherals, but you would need to use some form of Java Native Interfacing (JNI) to properly "access" them. JNI can be a mess to support cross-platform (i.e. distributing DLLs and SOs with your JAR) so...

What most Java Applets do is access the locally installed printers and use the standard Java Printing libraries. This is how we do it over at the qz-print project and you're free to review our source code here: https://github.com/qzindustries/qz-print/tree/master/qz-print/src/qz which uses threads fired by init() and boolean flags to fire all privileged functions.



回答2:

I am not sure of the answer to your question, but have an experiment that should shed further light on the matter.

In the opening lines of the Applet.init() call System.setSecurityManager(null). Then try to connect to the USB.

  • If the applet is trusted, the call to setSecurityManager(null) will succeed, and remove the last remnants of the SecurityManager. (Yes, even trusted applets have a security manager, it is just much less restrictive that the security manager for sand-boxed apps.)
  • If the USB is now discovered, it indicates a change in the trusted security manager. There have been a number of such changes in recent times.

Note that I am not suggesting putting code like this into production. If your applet is running in the same JRE as other applets, nullifying the SM could also elevate the privileges of the other applets.



回答3:

I had a similar problem with an Epson TM-H6000III on XP and Win7 32bit using JRE 1.6. Administrators could use the device, but "Users" could not. Java console was reporting:

Sep 23, 2011 3:38:47 PM com.xxxx.printer.epson.EpsonPrinter findPrinter
INFO: Error opening PrinterIII: jpos.JposException: 
    Could not connect to service with logicalName = 
    PrinterIII: Exception.message=Property or stream open error.

It appears the JRE installation had permission issues. Reinstalling JRE quickly cleared the problem.



回答4:

I received feedback from the Star Micronics team that their '...javapos drivers do not support web browser printing.'

BTW, System.setSecurityManager(null) turned out to be a great way to disambiguate any issues I was having that seemed to be related to security. Thanks Andrew.