Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
A Selenium extension for Tor Browser.
# before_all
require 'selenium_tor'
options = Selenium::WebDriver::Tor::Options.new
@driver = Selenium::WebDriver.for :tor, options: options
When you are done don't forget to quit the driver. Failure to do so may leave orphaned tor processes.
# after_all
@driver&.quit
Once you have a driver instance:
@driver.get 'https://check.torproject.org'
@driver.title
# => "Congratulations. This browser is configured to use Tor."
I can use Firefox with Selenium and set a SOCKS proxy to use the Tor network, so why the need?
The above approach will hide your IP, but there is a good chance your browser's unique or near-unique fingerprint may be logged by site owners. Subsequent visits could identify you. A primary aim of this project is to enable Selenium to leverage Tor Browser's unique anonymity characteristics - in particular its resistance to browser fingerprinting. The aim is to ensure Selenium Tor site visits leave an identical fingerprint to the thousands of regular Tor Browser users.
Install the gem and add to the application's Gemfile by executing:
$ bundle add selenium_tor
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install selenium_tor
Tor Browser. Versions >= 14.0 stable are supported.
As with Firefox browser, geckodriver
needs to be installed and in your PATH.
The gem needs to know the location of the Tor Browser Bundle (TBB). The Tor Browser download package archive must be extracted and the root TBB directory (named "tor-browser") placed somewhere on your system. By default it is assumed to be in the current user's HOME directory. An alternative location can be set via the env var TOR_BROWSER_ROOT_DIR
- e.g. export TOR_BROWSER_ROOT_DIR=/home/<user>/Downloads
. The Tor Browser binary location is automatically set by reference to this directory, so there is no need to do this:
options = Selenium::WebDriver::Tor::Options.new
options.binary = '/some/path/to/tor_firefox_binary' # UNNECESSARY
# => '/some/path/to/tor_firefox_binary'
The location of the TBB is not expected to change during code execution.
Tor Selenium is tested on Linux only right now.
A configuration option to patch the libxul.so packaged with Tor Browser is provided. This has the effect of preventing websites from fingerprinting Selenium-driven Tor Browser via a JS call to navigator.webdriver
:
@driver_class = Selenium::WebDriver::Tor::Driver
@driver_class.libxul_patched? # is Tor Browser's libxul.so patched?
# => false
@driver_class.patch_libxul # patch libxul.so
@driver_class.libxul_patched?
# => true
@driver_class.unpatch_libxul # revert the patch and restore the libxul.so packaged with Tor Browser
# => 0
The patcher uses the Bsdiff gem, which in turn requires the bzip2 library (libbz2-dev
).
require 'selenium_tor'
# => false
Tor Browser is based on Firefox, so for usage please read the Selenium docs for Firefox browser.
If the tor network is inaccessible for any reason a Selenium::WebDriver::Error::TimeoutError
will result.
A separate tor process is used for each driver. Failure to call Driver#quit
after code execution may leave orphaned tor processes.
In addition to the regular Firefox options, a :tor_opts key may be passed to an instance of Tor::Options
with a hash of tor options. All valid tor options are recognized - see man tor
. For convenience, "SocksPort" and "ControlPort" options may be set using snake_case symbols - i.e. :socks_port and :control_port. Additionally, a :tor_opts timeout value may be set with the :timeout key. This overrides the default time allowed for the tor process to bootstrap (10 seconds).
Running multiple tor processes requires that each uses different ports for SocksPort (and ControlPort, if used). These must be passed using the :tor_opts
key. An example using the Parallel gem:
require 'parallel'
@socks_port = 9150
@control_port = 9151
def driver
@socks_port += 2
@control_port += 2
options = Selenium::WebDriver::Tor::Options.new tor_opts: { socks_port: @socks_port, control_port: @control_port }
Selenium::WebDriver.for :tor, options: options
end
@drivers = [driver, driver]
::Parallel.all?(@drivers, in_threads: @drivers.size) do |driver|
driver.get 'https://check.torproject.org'
end
@drivers.each(&:quit)
# => truthy
You can get and set the security level (shield icon in TB) as follows. 4 is 'Standard', 2 is 'Safer', 1 is 'Safest'.
@driver.security_level
# => 4
@driver.security_level = 2
@driver.security_level
# => 2
You can get a new circuit for the current page ('New Tor circuit for this site' on TB's application menu):
@driver.new_circuit_for_site # new circuit for the current page domain
# => nil
You can get and set Driver preferences dynamically like this. Caveat emptor.
@driver.pref['browser.download.dir']
# => ''
@driver.pref['browser.download.dir'] = '/home/user/Downloads'
@driver.pref['browser.download.dir']
# => '/home/user/Downloads'
The Selenium::WebDriver::Tor
namespace is used for Driver
, Options
, Profile
and all tor-specific classes. Otherwise Selenium's Selenium::WebDriver::Firefox
namespace is used.
Remote functionality is not tested, but may be if a suitable Tor Browser Docker container becomes available.
A number of constants are set during driver initialization based upon values found in the Tor Browser Bundle (TBB) root directory - see below. These include:
Tor = Selenium::WebDriver::Tor
Tor::TBB_DIR # path to the TBB root directory
Tor::TBB_BROWSER_DIR # path to the 'Browser' directory in the above
Tor::TBB_BINARY_PATH # path to the firefox binary
Tor::TBB_TOR_BINARY_PATH # path to the bundled tor binary
Tor::TBB_PROFILE_DIR # path to the default profile directory
Tor::TBB_EXTENSIONS_DIR # path to the 'extensions' directory in the above
Tor::TBB_VERSION # the version installed, e.g. "13.0.1", note: driver.capabilities.browser_version returns the Firefox version Tor Browser is based on
# => instance_of String
Known issues are recorded here.
The gem uses Xvfb to allow Tor Browser to be manipulated headlessly. Xvfb in turn uses llvmpipe
software acceleration which may lead to issues with WebGL fingerprinting - see issue #7. If this is a problem we recommend using VirtualGL to force Xvfb to use your hardware driver instead. This is done by prepending your executable code with the command vglrun
. For an example see the section below on testing. VirtualGL can be installed from a package repo.
After checking out the repo, run bin/setup
to install dependencies.
Tests dependencies are [bsdiff](https://www.daemonology.net/bsdiff)
, VirtualGL
(see Fingerprinting above) and Xvfb
if you want to run headless tests.
Tests are run in the display set by the DISPLAY
env var, usually :0 by default. To run headless tests, set it to another value:
$ DISPLAY=:99 bundle exec rake
If you find driver instantiation failing with port bind failure error messages ( these include "Address already in use. Is Tor already running?") check you have no other tor processes running with conflicting ports. With timeout errors, you may also want to check the Tor network is actually up, it isn't always..
If you wish run the vglrun
WebGL fingerprint test install VirtualGL (see above, assumes you have the relevent drivers installed) and run the following command:
$ DISPLAY=:99 vglrun bundle exec ruby test/features/fingerprinting/vglrun_test_fingerprintjs.rb
You can run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
.
Bug reports and pull requests are welcome on GitLab at https://gitlab.com/matzfan/selenium-tor. For a pull request please checkout a suitably named feature branch before making and submitting changes.
The gem is available as open source under the terms of the MIT License.
FAQs
Unknown package
We found that selenium_tor demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.